20200518のPHPに関する記事は12件です。

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-opcache

Composer をインストール

$ 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/02364adacf36410f449e

AWS 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 install
phpに書き込んで終了
require '/path/to/sdk/vendor/autoload.php';

終了

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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ではインスタンス変数と呼ぶ



表にして眺めてみると違いや、規則性がわかりやすい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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文字列の場合



表にして眺めてみると違いや、規則性がわかりやすい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ファイルをダウンロードさせる方法

リンククリックでファイルをダウンロードさせる方法についてまとめました。

右クリック→リンク先を保存ではなく、リンクボタンをクリックしただけでダウンロードさせるという方法です。

画像などの単体ファイルをダウンロードさせる

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引数で指定してあげると可能です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

学習記録@PHP#1(cookieとsessionについて)

cookieとは

ブラウザ内に用意された簡易データベース。
ページをまたぐ変数の保存場所。
cookieはサーバー側ではなくクライアント側で保存。

【弱点】
セキュリティの低さ。
cookieはテキストファイルで作られており、中身を簡単に読み書きできる。
cookieジャック:cookieをファイルごと盗む。

sessionとは

ページをまたいで使える変数のような仕組みでセキュリティがcookieより高い。
ページをまたがる情報をサーバーサイド(PHP)で記録する。

cookieとsessionの使い分け

基本はすべてcookieを使用。
その上で、書き換えや盗難を防ぎたい場合にsessionを使用する。

cookie session
セキュリティ 低い 高い
有効期間 自由に設定 ブラウザ終了まで
データ量 制限なし 制限ありが多い
データ型 string型 制限なし
多言語との連携 ×
記録場所 クライアントサイド サーバーサイド

以上。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

「SQLSTATE[HY000] [2002] Connection refused」エラーの解決法

sql.png

Cloud9でLaravelを使った開発をしていたら画像のようなエラーが出ました。

初めは何かわからなかったけど、原因と対策は簡単。

コマンドで初めにSQLサーバーを起動していなかったというだけでした。

開発環境

・Windows10
・AWS(Cloud9)
・Larabel

解決法

初めにSQLサーバーを起動することが必要です。

◎SQLサーバ起動

$ sudo service mysqld start

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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'=>'なし');
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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.php
function 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.php
function 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にアクセストークンを入れて叩きます。

↓みたいな表組みで表示されるようにしてます。
スクリーンショット 2020-05-18 12.19.28.png

'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 Bitlink

bit.ly API v3 との違い

実は、v3ではフリーアカウントでも古いURLの30日以上前のカウント数が取れたのですが、v4が稼働してからは取れなくなりました。
API叩けば有料と同等の数が取れちゃうのどうなのかなって思ってたので、予想はしてましたけど。

Pricingを見る限り、CUSTOMIZEDじゃないとあんまり旨味はないですね。
FreeもBasicも、Link Reporting が30dayになっています。なので、APIで取得できる日数も30dayまでに制限がされています。

Basicで60dayとかにしたらユーザー増えそうなのになぁ。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【はじめからていねいに】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

アップグレードに成功していますね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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.
    

原因

  • すでにインストール済みのものをインストールしようとしてしまっていた。
  • そもそも実行する必要のないコマンドを実行してエラーが出てしまっていた。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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 もオプションに追加します。

Screen Shot 2020-05-18 at 10.27.41.png

***PASSWORDや***_KEY、***_SECRETなどは自動でマスクしてくれる模様。サジェストされた環境変数を選択して保存すると、`$SOME_KEY` 、つまり環境変数名 が保存されます。

環境変数名から値を取得する

上記の通り、保存された設定内容は 環境変数名 になります。このままだと、.envの値を利用できません。環境変数名から.envの値を取得するには、getenv()を使うのではなく、以下のように記述します。

Craft::parseEnv(MyPlugin::getInstance()->settings->secretKey);

Craft::parseEnv()を利用すると、$からスタートする値は.envの値、それ以外はその値そのものを返します。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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のキャッシュファイルができるため、
キャッシュすることができなかった。
解決する方法としては

  1. ホスト側でcomposer installする。
  2. ホスト側とコンテナ側で依存ライブラリのディレクトリをマウントして同期させる

今回は1の方法を取りたいと思います。

buildspecファイルの内容は以下になります。

buildspec.yml
version: 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.yml
version: 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キャッシュ利用時
スクリーンショット 2020-05-17 19.17.21.png

ローカルキャッシュ(カスタムキャッシュモード)利用時
スクリーンショット 2020-05-18 0.18.44.png

今回のケースでいうとS3キャッシュを利用する方が早く終わりました。

備考(インフラ構成図)

インフラ設計図.png
色々使用しておりますが、今回関係のある箇所は赤枠で囲われた部分になります。
CodePipeline,CodeBuild,CodeDeployを使用してECSにデプロイをしております。

最後に

今回のS3とカスタムキャッシュで、composerのキャッシュを利用した場合、S3の方が早かったですが、ローカルキャッシュは他にも2つのキャッシュモードがあるため、それを合わせて利用すれば早くなりそうです。(実際に試したが、Docker レイヤーキャッシュモードがキャッシュ利用できなかったので、今度調べてみようと思います。)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む