- 投稿日:2020-05-18T23:34:56+09:00
AWS EC2でAWS SDK for PHPインストール(PHP7.2+Apache2.4.41 + OPCashe + Composer)
Amazon Linux EC2でAPI叩いてからDynamoDBに保存するときに
PHPでやりたかったので、AWS SDK for PHPを入れようとしました。しかし、色々課題が発生したので、備忘録にします。自分用ですが、
対象読者は、「色々やったけど調べる内に、ここに行き着いた人」です。
助力になれば、幸いです。$ cat /etc/system-release Amazon Linux release 2 (Karoo)AmazonLinux2 ExtrasLibraryで PHP7.2をインストール
$ sudo amazon-linux-extras install php7.2 $ sudo yum install php php-mbstring $ sudo yum list installed | grep php php-cli.x86_64 7.2.30-1.amzn2 @amzn2extra-php7.2 php-common.x86_64 7.2.30-1.amzn2 @amzn2extra-php7.2 php-fpm.x86_64 7.2.30-1.amzn2 @amzn2extra-php7.2 php-json.x86_64 7.2.30-1.amzn2 @amzn2extra-php7.2 php-mysqlnd.x86_64 7.2.30-1.amzn2 @amzn2extra-php7.2 php-pdo.x86_64 7.2.30-1.amzn2 @amzn2extra-php7.2参考:https://qiita.com/owlbeck/items/20f3e5402cb782f6291e
Apache をインストール
$ sudo yum install httpd $ systemctl start httpd $ systemctl status httpd ● httpd.service - The Apache HTTP Server Active: active (running)OPCashe をインストール
sudo yum install php-opcacheComposer をインストール
$ curl -sS https://getcomposer.org/installer | php $ ls composer.phar $ php composer.phar $ mv composer.phar /usr/local/bin/composer $ composer最後の二行はPATHが通っている場所に引っ越しただけです。これでかっこいいロゴを表示できます。
参考:https://getcomposer.org/doc/00-intro.md
参考:https://qiita.com/kakijin/items/02364adacf36410f449eAWS SDK for PHP の使用開始
$ sudo -i $ cd /usr/local/bin/composer $ vi composer.json //jsonに書き込みcomposer.json{ "require": { "aws/aws-sdk-php": "2.*" } }$ php composer.phar installphpに書き込んで終了require '/path/to/sdk/vendor/autoload.php';終了
- 投稿日:2020-05-18T20:09:36+09:00
pythonとphpの違いまとめ(主要項目の対比表)
pythonとphpの違いまとめ(主要項目の対比表)
pythonとphpのクラスやメソッドなど主要項目の違いまとめ。
どっちがどっちかわからくなるの防止。
項目 Python PHP 関数 def 関数名(): function 関数名(): 処理の終わり 改行 ; 変数 変数名 $変数名 クラス定義 class クラス名: class クラス名{} コンストラクタ def __init__(self,): アクセス権 function __construct(){} インスタンス クラス名() new クラス名() プロパティ *1 インスタンス.プロパティ名 $プロパティ名 プロパティの呼び出し インスタンス名.プロパティ名 インスタンス->プロパティ名 インスタンス自身 self $this 自身のプロパティ呼び出し self.プロパティ名 $this->プロパティ名 メソッド def メソッド名(self,) アクセス権 function メソッド名() メソッド呼び出し インスタンス.メソッド名() インスタンス->メソッド名() 継承 class クラス名(親クラス名): class クラス名 extends 親クラス名{} ファイル読込み import モジュール名 require_once(' ') クラス読込み from モジュール名 import クラス名 require_once(' ') 親クラスのメソッド呼び出し super().メソッド名() parent::メソッド名() クラスメソッド @classmethod アクセス権 static function メソッド名(){} クラスメソッドの呼び出し クラス名.メソッド名() クラス名::メソッド名() クラスプロパティ なし(?) アクセス権 static $プロパティ名 クラスプロパティの呼び出し なし(?) クラス名::$プロパティ名 出力 print() echo/print 配列 [] array() for文 for 変数 in 配列など: for($i=初期値: 条件式: ステップ){} 配列からひとつずつ抜き出す for 変数 in 配列: foreach($変数名 as 配列) if文 if 条件式: if(条件式){} else if elif elseif switch文 なし switch(){case 条件: 処理; break;} and and &&/and or or パイプ2本/or インクリメント演算子 なし ++ デクリメント演算子 なし -- 整数型に変換 int() intval() 文字列型に変換 str() strval() 小数点に型変換 float() floatval() 3桁区切り '{:,d}'.format(数値) number_format() *1:pythonではインスタンス変数と呼ぶ
表にして眺めてみると違いや、規則性がわかりやすい。
- 投稿日:2020-05-18T20:09:36+09:00
PythonとPHPの違いまとめ(主要項目の対比表)
PythonとPHPの違いまとめ(主要項目の対比表)
pythonとphpのクラスやメソッドなど主要項目の違いまとめ。
どっちがどっちかわからくなるの防止。
項目 Python PHP 関数 def 関数名(): function 関数名(){} 処理の終わり 改行 ; コメントアウト # // or /* */ 変数 変数名 $変数名 クラス定義 class クラス名: class クラス名{} コンストラクタ def __init__(self): アクセス権 function __construct(){} インスタンス クラス名() new クラス名() プロパティ *1 プロパティ名 $プロパティ名 プロパティの呼び出し インスタンス.プロパティ名 インスタンス->プロパティ名 インスタンス自身 self $this 自身のプロパティ呼び出し self.プロパティ名 $this->プロパティ名 メソッド def メソッド名(self) アクセス権 function メソッド名() メソッド呼び出し インスタンス.メソッド名() インスタンス->メソッド名() 継承 class クラス名(親クラス名): class クラス名 extends 親クラス名{} ファイル読込み import モジュール名 require_once(' ') クラス読込み from モジュール名 import クラス名 require_once(' ') 親クラスのメソッド呼び出し super().メソッド名() parent::メソッド名() クラスメソッド @classmethod
def メソッド名():アクセス権 static function メソッド名(){} クラスメソッドの呼び出し クラス名.メソッド名() クラス名::メソッド名() クラスプロパティ (メソッド定義と同列に)
プロパティ名アクセス権 static $プロパティ名 クラスプロパティの呼び出し クラス名.プロパティ名 クラス名::$プロパティ名 出力 print() echo/print 配列 [] array() キーあり配列 {キー名:値} array(キー名=>値) キーあり配列呼び名 辞書型 連想配列 配列の要素数 len(配列) count(配列) 変数展開*2 f'{変数}' "${変数}" for文 for 変数 in range(始値, 終値, ステップ)
※ 終値は含まないfor($変数名=初期値: 条件式: ステップ){} 配列からひとつずつ抜き出す for 変数 in 配列: foreach($変数名 as 配列) if文 if 条件式: if(条件式){} else if elif 条件式: elseif (条件式){} switch文 なし switch(){case 条件: 処理; break;} and and &&/and or or パイプ2本/or インクリメント演算子 なし ++ デクリメント演算子 なし -- 整数型に変換 int() intval() 文字列型に変換 str() strval() 小数点に型変換 float() floatval() 3桁区切り '{:,d}'.format(数値)
f'{数値:,d}'number_format() *1. pythonではインスタンス変数と呼ぶ
*2. PHP:シングルクオテーションだと文字列として出力
python:f文字列の場合
表にして眺めてみると違いや、規則性がわかりやすい。
- 投稿日:2020-05-18T17:02:02+09:00
ファイルをダウンロードさせる方法
リンククリックでファイルをダウンロードさせる方法についてまとめました。
右クリック→リンク先を保存ではなく、リンクボタンをクリックしただけでダウンロードさせるという方法です。
画像などの単体ファイルをダウンロードさせる
index.html<a href="ファイル名" download>ファイルをダウンロード</a>リンクしたファイルがダウンロードされます。
ダウンロードされるファイルに名前をつけたい場合
index.html<a href="ファイル名" download="ダウンロードした後のファイル名">ファイルをダウンロード</a>リンクするファイルのファイル名と、ダウンロードされるファイルのファイル名を変えたい場合は、
download=""
にファイル名を指定するとできます。フォルダ内をまとめてダウンロードする
サーバーに上がっているファルダの中身をフォルダごとzipにまとめてダウンロードする場合、zip化するphpを叩いてダウンロードする、がシンプルかなと思います。
phpの
ZipArchive
クラスを使います。zip.php<?php $zipName = $_GET['dl']; // 圧縮するフォルダ名 $dist = $zipName.'.zip'; // 生成する圧縮ファイル名 $path = 'フォルダまでのパス'.$zipName; // 圧縮するフォルダのパス //DLするファイルのフォルダ構成を維持するか否か 0:しない/1:する //維持する場合、ダウンロードしたファイルは $path の構成になります $filePath = 0; //DLファイルが1つの場合、フォルダに入れるか否か 0:いれない/1:いれる $folderIn = 1; $zip = new ZipArchive(); $zip->open($dist, ZipArchive::CREATE | ZipArchive::OVERWRITE); if (is_dir($path)) { $files = array_diff(scandir($path), ['.', '..']); $filesNum = count($files); foreach ($files as $file){ if($filePath >= 1){ //フォルダ構成を維持する $zip->addFile($path.'/'.$file); }else{ //維持しない if(($folderIn >= 1) && ($filesNum <= 1)){ //ファイルが1つの時、フォルダに収める場合の処理 $localFile = $zipName.'/'; }else{ $localFile = ''; } $zip->addFile($path.'/'.$file, $localFile.$file); } } } $zip->close(); // ストリームに出力 header('Content-Type: application/zip; name="' . $dist . '"'); header('Content-Disposition: attachment; filename="' . $dist . '"'); header('Content-Length: '.filesize($dist)); echo file_get_contents($dist); // 一時ファイルを削除しておく unlink($dist); exit; ?>index.html<a href="zip.php?dl=フォルダ名">ファイルをダウンロード</a>圧縮するファイルにフォルダを指定していても、フォルダ内のファイルが1つしかない場合、解凍するとファイルだけ、ということが起きるので、
$zip->addFile
の第2引数でフォルダ内に収めるようにしています。ダウンロードされたファイルに特定の名前などを指定したい場合も、
$zip->addFile
の第2引数で指定してあげると可能です。
- 投稿日:2020-05-18T14:45:49+09:00
学習記録@PHP#1(cookieとsessionについて)
cookieとは
ブラウザ内に用意された簡易データベース。
ページをまたぐ変数の保存場所。
cookieはサーバー側ではなくクライアント側で保存。【弱点】
セキュリティの低さ。
cookieはテキストファイルで作られており、中身を簡単に読み書きできる。
cookieジャック:cookieをファイルごと盗む。sessionとは
ページをまたいで使える変数のような仕組みでセキュリティがcookieより高い。
ページをまたがる情報をサーバーサイド(PHP)で記録する。cookieとsessionの使い分け
基本はすべてcookieを使用。
その上で、書き換えや盗難を防ぎたい場合にsessionを使用する。
cookie session セキュリティ 低い 高い 有効期間 自由に設定 ブラウザ終了まで データ量 制限なし 制限ありが多い データ型 string型 制限なし 多言語との連携 〇 × 記録場所 クライアントサイド サーバーサイド 以上。
- 投稿日:2020-05-18T13:56:55+09:00
「SQLSTATE[HY000] [2002] Connection refused」エラーの解決法
- 投稿日:2020-05-18T13:34:06+09:00
PHPの矢印の意味 アロー演算子「->」とダブルアロー演算子「=>」
アロー演算子「->」
アロー演算子はその左辺にはクラスのインスタンスを取り、右辺には左辺のクラスが持つプロパティ(変数)やメソッド(関数)を指定しプロパティへのアクセス・メソッドの呼び出しを実行します。
// 人間クラス class Person { $name; function __construct($name) { $this->name = $name; } function introduceSelf() { echo "私の名前は". $this->name"です"; } } $taro = new Person("太郎"); echo $taro->$name; $taro->introduceSelf();ダブルアロー演算子「=>」
連想配列キーとバリューを示すためのもの
return view('buy/index', ['cartitems' => $cartitems, 'subtotal'=> $subtotal]); $array = array('apple'=>'りんご', 'peach'=>'もも', 'pear'=>'なし');
- 投稿日:2020-05-18T12:35:01+09:00
Bitly API v4で短縮URLを展開、クリック数を取得する方法
bit.ly API v3が終了してしまったので、bit.ly API v4に移行しようと使い方を調べたものの情報があまりないので、メモがてら置いておきます。
bitlyのダッシュボードがとんでもなく見辛いので見やすくするために書きました。
(棒グラフにマウスオーバーしないと数字がわからないって本当にどうかと思う)ここでは、短縮URLの展開(元のURLに戻す)と、短縮URLがクリックされた数を取得する方法を記載しています。
APIを使用して、短縮URLを取得する方法は、以下のサイトを参考にしてください。》短縮URL生成サイト「bit.ly」のAPIv4へのマイグレーションの方法
bit.ly API を使い始める前に
bit.ly APIを使用するには、アクセストークンが必要になります。
アカウントを取得→アクセストークンを取得しておいてください。アクセストークンを取得する方法は、以下のサイトがわかりやすいと思います。
》bitlyのAPIアクセストークンを取得できない?パスワード入力の場所が変わってたbit.ly APIで短縮URLを展開する
index.phpfunction LinkExpand($url, $token){ $baseurl = 'https://api-ssl.bitly.com/v4/expand'; if(strpos($url,'https') !== false){ $url = substr($url, 8); }else{ $url = substr($url, 7); } $ch = curl_init($baseurl); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['bitlink_id' => $url])); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_HTTPHEADER, [ "Authorization: Bearer ". $token, "Content-Type: application/json", "Host: api-ssl.bitly.com", "Accept: application/json" ]); $results = json_decode(curl_exec($ch)); $link = $results->long_url; echo $link; }
$url
に短縮URL、$token
にアクセストークンを入れて叩きます。
bitlink_id
は、短縮URLからhttps://
を削除したものみたいです。bit.ly API でクリック数を取得する
index.phpfunction LinkAnalysis($url, $token){ date_default_timezone_set("Asia/Tokyo"); if(strpos($url,'https') !== false){ $url = substr($url, 8); }else{ $url = substr($url, 7); } $api = 'https://api-ssl.bitly.com/v4/bitlinks/'.$url.'/clicks'; $ch = curl_init($api); curl_setopt($ch, CURLOPT_GETFIELDS, json_encode(['unit'=>'day','units'=>-1])); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_HTTPHEADER, [ "Authorization: Bearer ".$token, "Content-Type: application/json" ]); $obj = json_decode(curl_exec($ch), true); if(!$obj){ echo 'データを取得できませんでした'; }else{ $revData = array_reverse($obj['link_clicks']); $allNum = 0; echo '<table><tr>'; foreach ($revData as $result){ $getDate = $result['date']; $getDate = date('m/d', strtotime($getDate)); echo '<th>'.$getDate.'</th>'; } echo '</tr><tr>'; foreach ($revData as $result){ $getClick = $result['clicks']; echo '<td>'.$getClick.'</td>'; $allNum += $getClick; } echo '</tr></table>'; echo '<p>合計:'.$allNum.'</p>'; } }
$url
に短縮URL、$token
にアクセストークンを入れて叩きます。
'unit'=>'day'
で取得データの形式を指定できます。
day(日別)の他、"minute"
、"hour"
、"day"
、"week"
、"month"
が指定できます。
'units'=>-1
で取得数を指定できます。-1
で全てのデータを取得します。
30日分しか取得できないので、'unit'=>'day'
の場合は-1
でいいと思います。途中で
array_reverse
してますが、そのままだと配列の順番が「現在→過去」になっているので、「過去→現在」に直しているだけです。そのほかの指定はAPIドキュメントをみてください。
》Bitly API V4 - Get Clicks for a Bitlinkbit.ly API v3 との違い
実は、v3ではフリーアカウントでも古いURLの30日以上前のカウント数が取れたのですが、v4が稼働してからは取れなくなりました。
API叩けば有料と同等の数が取れちゃうのどうなのかなって思ってたので、予想はしてましたけど。Pricingを見る限り、CUSTOMIZEDじゃないとあんまり旨味はないですね。
FreeもBasicも、Link Reporting が30dayになっています。なので、APIで取得できる日数も30dayまでに制限がされています。Basicで60dayとかにしたらユーザー増えそうなのになぁ。
- 投稿日:2020-05-18T12:13:41+09:00
【はじめからていねいに】PHP7.4にアップグレードする方法
はじめに
PHPのバージョンが7.2だったので最新のphp7.4にアップグレードしようとしたところつまずいたので備忘録に残しておきます。
手順
まずは自分の環境で使用しているPHPのバージョンを確認してみましょう!
僕の場合はphp7.2.30がインストールされていました。$ php -v PHP 7.2.30 (cli) (built: Apr 23 2020 02:40:39) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies with Zend OPcache v7.2.30, Copyright (c) 1999-2018, by Zend Technologies次にhomebrewでphpを検索します。
$ brew search php@7 ==> Formulae php@7.2 ✔ php@7.3 php@7.4 ✔brewでphp7.4をインストールします。
$ brew install php@7.4インストールが完了したらPATHを通します。
export PATH="/usr/local/opt/php@7.4/bin:$PATH" export PATH="/usr/local/opt/php@7.4/sbin:$PATH"php7.4をインストールしたしPATHも通したのでこれで完了のはずです!
って意気揚々としていたら、、、あれ??バージョン変わってない。(僕の場合)$ php -v PHP 7.2.30 (cli) (built: Apr 23 2020 02:40:39) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies with Zend OPcache v7.2.30, Copyright (c) 1999-2018, by Zend Technologiesバージョンが変わっていなかった人向け
手順に沿ってインストールしたつもりが、バージョンが変わっていない人は下記を試してください。
もう1度php7.4をインストールしてみる。
$ brew install php@7.4 Warning: php 7.4.6 is already installed and up-to-date To reinstall 7.4.6, run `brew reinstall php`警告が出ていますね。もうすでにインストールしているよって言われてます。
そして、To reinstall 7.4.6, run `brew reinstall php
`とも言われていますね。警告にしたがってコマンドを実行しましょう。
$ brew reinstall php ==> Reinstalling php ==> Downloading https://homebrew.bintray.com/bottles/php-7.4.6.catalina.bottle.tar.gz Already downloaded: /Users/owner/Library/Caches/Homebrew/downloads/01f6c132bb17669a60cff79a15ce162bd084f81177e74902669d7a2033872a8d--php-7.4.6.catalina.bottle.tar.gz ==> Pouring php-7.4.6.catalina.bottle.tar.gz ==> /usr/local/Cellar/php/7.4.6/bin/pear config-set php_ini /usr/local/etc/php/7.4/php.ini system ==> /usr/local/Cellar/php/7.4.6/bin/pear config-set php_dir /usr/local/share/pear system ==> /usr/local/Cellar/php/7.4.6/bin/pear config-set doc_dir /usr/local/share/pear/doc system ==> /usr/local/Cellar/php/7.4.6/bin/pear config-set ext_dir /usr/local/lib/php/pecl/20190902 system ==> /usr/local/Cellar/php/7.4.6/bin/pear config-set bin_dir /usr/local/opt/php/bin system ==> /usr/local/Cellar/php/7.4.6/bin/pear config-set data_dir /usr/local/share/pear/data system ==> /usr/local/Cellar/php/7.4.6/bin/pear config-set cfg_dir /usr/local/share/pear/cfg system ==> /usr/local/Cellar/php/7.4.6/bin/pear config-set www_dir /usr/local/share/pear/htdocs system ==> /usr/local/Cellar/php/7.4.6/bin/pear config-set man_dir /usr/local/share/man system ==> /usr/local/Cellar/php/7.4.6/bin/pear config-set test_dir /usr/local/share/pear/test system ==> /usr/local/Cellar/php/7.4.6/bin/pear config-set php_bin /usr/local/opt/php/bin/php system ==> /usr/local/Cellar/php/7.4.6/bin/pear update-channels ==> Caveats To enable PHP in Apache add the following to httpd.conf and restart Apache: LoadModule php7_module /usr/local/opt/php/lib/httpd/modules/libphp7.so <FilesMatch \.php$> SetHandler application/x-httpd-php </FilesMatch> Finally, check DirectoryIndex includes index.php DirectoryIndex index.php index.html The php.ini and php-fpm.ini file can be found in: /usr/local/etc/php/7.4/ To have launchd start php now and restart at login: brew services start php Or, if you don't want/need a background service you can just run: php-fpm ==> Summary ? /usr/local/Cellar/php/7.4.6: 519 files, 76.1MB再度、phpのバージョンを確認します!
$ php -v PHP 7.4.6 (cli) (built: May 14 2020 10:38:36) ( NTS ) Copyright (c) The PHP Group Zend Engine v3.4.0, Copyright (c) Zend Technologies with Zend OPcache v7.4.6, Copyright (c), by Zend Technologiesアップグレードに成功していますね。
- 投稿日:2020-05-18T12:04:50+09:00
composerでrequireなどをするとインストールに失敗する
目的
- require時に発生するエラーを解決した話をまとめる
実施環境
- ハードウェア環境(下記の二つの環境で確認)
項目 情報 OS macOS Catalina(10.15.3) ハードウェア MacBook Pro (16-inch ,2019) プロセッサ 2.6 GHz 6コアIntel Core i7 メモリ 16 GB 2667 MHz DDR4 グラフィックス AMD Radeon Pro 5300M 4 GB Intel UHD Graphics 630 1536 MB
- ソフトウェア環境
項目 情報 備考 PHP バージョン 7.4.3 Homwbrewを用いて導入 Laravel バージョン 7.0.8 commposerを用いて導入 MySQLバージョン 8.0.19 for osx10.13 on x86_64 Homwbrewを用いて導入 エラー内容
laravel/uiをインストールしようと思い下記のコマンドを実行した。
$ composer require laravel/ui下記の様なエラーが発生しインストールが失敗してしまった。
>Using version ^2.0 for laravel/ui >./composer.json has been updated >Loading composer repositories with package information >Updating dependencies (including require-dev) >Nothing to install or update >Generating optimized autoload files >> Illuminate\Foundation\ComposerScripts::postAutoloadDump >> @php artisan package:discover --ansi >Discovered Package: facade/ignition >Discovered Package: fideloper/proxy >Discovered Package: fruitcake/laravel-cors >Discovered Package: laravel/tinker >Discovered Package: laravel/ui >Discovered Package: nesbot/carbon >Discovered Package: nunomaduro/collision >Package manifest generated successfully. >10 packages you are using are looking for funding. >Use the `composer fund` command to find out more! >Installation failed, reverting ./composer.json to its original content.原因
- すでにインストール済みのものをインストールしようとしてしまっていた。
- そもそも実行する必要のないコマンドを実行してエラーが出てしまっていた。
- 投稿日:2020-05-18T10:43:38+09:00
CraftCMSのプラグイン設定画面で.envの値をサジェストする
CraftCMSで独自プラグインやモジュールを開発する際に、外部サービスのAPIキーやメールアドレスなどを設定することがあります。この設定に.envの値を利用することができますが、設定じに、サジェストしてユーザが選択しやすいようにすることができます。
サジェスト機能付きテキストフィールド設定
templates/settings.twig{% import "_includes/forms" as forms %} {{ forms.autosuggestField({ label: "Secret Key"|t('plugin-handle'), id: 'secret-key', name: 'secretKey', value: settings.secretKey, suggestAliases: true, suggestEnvVars: true }) }}
forms.autosuggestField
を使うことで、サジェスト機能付きのテキストフィールドを出力できます。これにsuggestEnvVars: true
をオプションに追加すると、テキストフィールドで先頭に$を入力すると.envの値を参照してサジェストしてくれます。設定値がファイルパスやURLなどの場合はsuggestAliases: true
もオプションに追加します。***PASSWORDや***_KEY、***_SECRETなどは自動でマスクしてくれる模様。サジェストされた環境変数を選択して保存すると、`$SOME_KEY` 、つまり環境変数名 が保存されます。
環境変数名から値を取得する
上記の通り、保存された設定内容は 環境変数名 になります。このままだと、.envの値を利用できません。環境変数名から.envの値を取得するには、getenv()を使うのではなく、以下のように記述します。
Craft::parseEnv(MyPlugin::getInstance()->settings->secretKey);
Craft::parseEnv()
を利用すると、$からスタートする値は.envの値、それ以外はその値そのものを返します。
- 投稿日:2020-05-18T00:55:43+09:00
AWS CodeBuildでcomposer installしたライブラリをキャッシュする
はじめに
Code兄弟のCodePipeline,CodeBuild,CodeDeployを利用してCI/CD環境を構築した際(ソースはBitBucket)に、
composer installしたライブラリをキャッシュする方法の記事がなく時間がかかったため作成します。なぜキャッシュをするのか
キャッシュをすることによりデプロイに、要する時間を短縮できるためサービスを早く提供することができるメリットがあります。
小規模なインフラ構成の場合は多少の時間しか短縮できませんが、少しでも短い方が良いと思うので是非参考にしていただければと思います。CodeBuildのキャッシュ機能
CodeBuildのキャッシュ機能は2通りあります
- S3キャッシュ
- 複数のビルドホスト間で利用できるキャッシュ
- ダウンロードするよりも構築にコストがかかる小規模な中間ビルドアーティファクトに適したオプション
- ネットワーク経由で転送するには長い時間がかかる場合があるため、大規模なビルドアーティファクトには適していません
- Docker レイヤーを使用する場合、これは最適なオプションではありません。
- ローカルキャッシュ(buildを実行するホストに保存する)
- ビルドホストのみが利用できるキャッシュをそのビルドホストにローカルに保存します
- キャッシュはビルドホストですぐに利用できるため、この方法は大規模な中間ビルドアーティファクトに適しています
AWS公式記事「AWS CodeBuild でのキャッシュのビルド」
ローカルキャッシュはキャッシュモードが3つある
キャッシュする内容を選ぶことができる、キャッシュモードが3つあります。
- ソースキャッシュモード
- Docker レイヤーキャッシュモード
- カスタムキャッシュモード
それぞれの内容は公式記事を参照してください。今回私のケースは以下
- 小規模なアプリ
- dockerを使用
- ビルドホストは1つ
せっかくなので実行の比較をしてみましょう。(composerのキャッシュの)
ローカルキャッシュとS3キャッシュの実行時間の比較
それぞれの設定で2回実行し、2回目の実行時間を比較します。
ローカルキャッシュに関しては、カスタムキャッシュモード
を使用してみます。buildspecファイルを作成する際にcacheを利用するようにする
codebuildを使用する際は、buildspecファイルを作成する必要があります。
そのファイルの記述の中で、キャッシュを利用することを記述する箇所があるため、そこにcompopserのcacheディレクトリを指定することで、
実現することができます。つまづいたポイント1
composer install
をdockerファイル内で実行していると、コンテナ内にcompoesrのキャッシュファイルができるため、
キャッシュすることができなかった。
解決する方法としては
- ホスト側で
composer install
する。- ホスト側とコンテナ側で依存ライブラリのディレクトリをマウントして同期させる
今回は1の方法を取りたいと思います。
buildspecファイルの内容は以下になります。
buildspec.ymlversion: 0.2 phases: install: ## ここでphpの実行環境のバージョンを指定する runtime-versions: php: 7.3 pre_build: commands: - $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION) - IMAGE_TAG=$CODEBUILD_RESOLVED_SOURCE_VERSION - REPOSITORY_URI=********.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/restful-api build: commands: ## ホスト側でcomposer install - composer install - docker build -t $REPOSITORY_URI:$IMAGE_TAG . - docker push $REPOSITORY_URI:$IMAGE_TAG post_build: commands: - echo Writing image definitions file... - printf '[{"name":"restful-api", "imageUri":"%s"}]' $REPOSITORY_URI:$IMAGE_TAG > imageDetail.json artifacts: files: - imageDetail.json ## ここがキャッシュを指定する箇所!!!! cache: paths: - '/root/.composer/**/*'注目していただきたいのは
cache
項目になります。つまづきポイント2
実際にbuild実行したところ、2回以上build実行しても、キャッシュが利用されている形跡がなく実行時間も短くなりません。
ローカルキャッシュのカスタムキャッシュ
は先ほどのbuild.specのままではdockerでは使えないという問題がわかりました。
原因は、以下の実行時のログを見ると気付きました。Symlinking: /root/.composer => /codebuild/local-cache/custom/a29cac2ab2bc5a9ecb43317ff3dd8847f93bf828b0606fda90fa7db63d27cebb/root/.composerローカルキャッシュのカスタムキャッシュの仕組みはキャッシュ対象のパスから、codebuildのキャッシュ用ディレクトリ(?)に対して、Symlinkを貼るという内容でした。
dockerではホスト・コンテナ間でのSymlinkはサポートしていないため、キャッシュが取れませんでした。(この事実を知るのに、かなり時間がかかったのに。。。)どうやって実現できるのかというと
大変参考になる方法を見つけたので、(参考記事「AWS CodeBuildのローカルキャッシュのCustom cacheでnode_modulesやvendorをキャッシュする
」)[https://tech.moyashidaisuke.com/entry/2019/03/19/205243]に対応方法を真似することにしました。buildspec_v2.ymlversion: 0.2 phases: install: ## ここでphpの実行環境のバージョンを指定する runtime-versions: php: 7.3 pre_build: commands: - $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION) - IMAGE_TAG=$CODEBUILD_RESOLVED_SOURCE_VERSION - REPOSITORY_URI=********.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/restful-api ## キャッシュを利用する - cp -r /root/.composer_cache/ /root/.composer/ build: commands: - composer install - docker build -t $REPOSITORY_URI:$IMAGE_TAG . - docker push $REPOSITORY_URI:$IMAGE_TAG post_build: commands: - echo Writing image definitions file... - printf '[{"name":"restful-api", "imageUri":"%s"}]' $REPOSITORY_URI:$IMAGE_TAG > imageDetail.json ## 最新のキャッシュファイルをローカルキャッシュ用ディレクトリにコピーする - cp -r /root/.composer/ /root/.composer_cache/ artifacts: files: - imageDetail.json cache: paths: - '/root/.composer/**/*'やっていることは、
1. カスタムキャッシュしたローカルキャッシュ用ディレクトリをキャッシュ利用したかったディレクトリにコピーする
2. build後に最新のキャッシュをローカルキャッシュ用ディレクトリにコピーしてあげる実行結果
今回のケースでいうとS3キャッシュを利用する方が早く終わりました。
備考(インフラ構成図)
色々使用しておりますが、今回関係のある箇所は赤枠で囲われた部分になります。
CodePipeline,CodeBuild,CodeDeployを使用してECSにデプロイをしております。最後に
今回のS3とカスタムキャッシュで、composerのキャッシュを利用した場合、S3の方が早かったですが、ローカルキャッシュは他にも2つのキャッシュモードがあるため、それを合わせて利用すれば早くなりそうです。(実際に試したが、Docker レイヤーキャッシュモードがキャッシュ利用できなかったので、今度調べてみようと思います。)