20190625のPHPに関する記事は21件です。

アロー演算子の可変関数についてメモ

可変関数について簡単にメモ。

ex)
class Person {
    public function sayHello() {
        echo "Hello.";
    }

    public function sayEvening() {
        echo "Good evening";
    }
}

$now = intval(date('H'));
if($now <= 16) {
    $greet = "sayHello";    
} else {
    $greet = "sayEvening";    
}

$person = new Person;
$person->$greet();

アロー関数時も、関数名を変数にいれて、

$person->$greet();

このように動的にメソッドを呼ぶことができる。

FWのモデルを呼ぶときにwhereメソッドなのか、andWhereメソッドなのか条件で場合分けするときに使ってみた。

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

アロー関数時の可変関数についてメモ

可変関数について簡単にメモ。

ex)
class Person {
    public function sayHello() {
        echo "Hello.";
    }

    public function sayEvening() {
        echo "Good evening";
    }
}

$now = intval(date('H'));
if($now <= 16) {
    $greet = "sayHello";    
} else {
    $greet = "sayEvening";    
}

$person = new Person;
$person->$greet();

アロー関数時も、関数名を変数にいれて、

$person->$greet();

このように動的にメソッドを呼ぶことができる。

FWのモデルを呼ぶときにwhereメソッドなのか、andWhereメソッドなのか条件で場合分けするときに使ってみた。

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

laravelをAWS EC2にデプロイする

はじめに

vagrantなどのローカル開発環境で作成したlaravelプロジェクトをAWSのEC2上にデプロイする時に色々迷ったので、まとめとしてあげます。本番サーバにAWSを使ってみたいという方に見て頂ければと思います。

環境

php7.2.18
apache2.4.39
laravel5.7
EC2(Amazon Linux AMI 2018.03.0 (HVM), SSD Volume Type 無料枠)
RDS(mysqlを使用)

前提

・ローカルで開発したプロジェクトをすでにgithubにプッシュ済み
・EC2にSSH接続できている
・EC2からRDSへ接続できる設定ができている(セキュリティグループなど)

PHP7.2インストール

インストールできるリスト確認
sudo yum list available | grep php72

インストール
sudo yum install -y \
  php72 php72-devel php72-fpm php72-gd php72-mbstring \
  php72-mysqlnd php72-pdo \
  php72-xml php72-json

インストール済みを確認
sudo yum list installed | grep php72

バージョン確認
php -v

Mysqlインストール RDSとの接続

インストール
sudo yum -y install mysql

接続
mysql test_db -h <エンドポイント> -P 3306 -u test_user -p

apacheインストール

sudo yum install -y httpd24

上記の流れでインストールを進めていると、なぜかすでにインストール済みと出た。
どこで入れたかわからなかった。
続きの設定を行っていく

wabサーバの起動
sudo service httpd start

システムがブートするたびにapacheが起動するよう設定
sudo chkconfig httpd on

有効か確認
chkconfig --list httpd

ドキュメントルートの権限変更

ユーザをapacheグループに追加
sudo usermod -a -G apache ec2-user

一旦ログアウト
exit

グループのメンバーシップを検証
groups

グループ所有権をapacheグループに変更
sudo chown -R ec2-user:apache /var/www

グループの書き込み許可追加
sudo chmod 2775 /var/www

サブディレクトにグループ ID を設定するには、/var/www とサブディレクトのディレクトリ許可
find /var/www -type d -exec sudo chmod 2775 {} \;

グループ書き込み許可を追加するには、/var/www とサブディレクトリのファイル許可を再帰的に変更します。
find /var/www -type f -exec sudo chmod 0664 {} \;

Gitインストール

sudo yum install git

composer自身のインストール

インストール
sudo curl -sS https://getcomposer.org/installer | php

パスを通す
sudo mv composer.phar /usr/local/bin/composer

LaravelプロジェクトのClone

cd /var/www/html
git clone <URL>

apacheのドキュメントルート設定

設定ファイルを開く
sudo vi /etc/httpd/conf/httpd.conf

以下に変更
DocumentRoot "/var/www/html/自分のlaravel_project/public

最終行に以下を追記
# .htaccess 有効化
<Directory /var/www/html/自分のlaravel_project/public>
    AllowOverride All
</Directory>

Laravelプロジェクトでcomposer インストール

cd /var/www/html/laravelプロジェクト
composer install

config, routeのキャッシュクリア

php artisan config:cache
php artisan route:cache

プロジェクトのパーミッション変更

chmod 777 storage -R
chmod 777 bootstrap/cache -R

.envの設定

git cloneしたLaravelプロジェクトには.envファイルがないので、
composer insatallで作成された、.env.exsampleを使用する

cp .env.example .env
vi .env

APP_URL=http://IPアドレス ←サーバーのIPにする

DB_CONNECTION=mysql
DB_HOST=←RDSのエンドポイント
DB_DATABASE=データベース名
DB_USERNAME=RDS作成時のユーザ名
DB_PASSWORD=設定したパスワード

キーを作成し、キャッシュをクリアする

php artisan key:generate
php artisan config:clear

テーブル作成

php artisan migrate

シンボリックリンクの作成

これは作成したアプリで画像アップロードしているような場合は必要かと思います。

php artisan storage::link

ブラウザで確認する

あとはブラウザでEC2のIPアドレスを入力するだけです!
ここまでくればブラウザで正しく表示されるかと思います!

参考

https://qiita.com/reflet/items/11ad79e01e808876caa1
https://nori-life.com/install-laravel-aws/
https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/install-LAMP.html
https://qiita.com/takg/items/9a044b36cdf216a42ba6
https://qiita.com/nbapps_dev/items/9307e6fc0edb59c09181

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

初心者がkonohaでVPSを借りてnginxでphpページを公開するまで -nginx・php-

nginxとphpをインストールして動かす

1:最新のnginxをインストールする

今回はapacheではなくてnginxでサーバーを立てようと思います。

#root権限で以下の作業を実行する
sudo -s

#nginx 公式サイトからPGPkeyをダウンロード
wget https://nginx.org/keys/nginx_signing.key

#PGPkeyを登録
apt-key add nginx_signing.key

#aptのリストに追記する
vi /etc/apt/sources.list
→ deb http://nginx.org/packages/ubuntu/ bionic nginx
→ deb-src http://nginx.org/packages/ubuntu/ bionic nginx

#aptのリストを更新
apt update

#nginxをaptでインストール
apt install nginx

#サーバー起動時にnginxも起動するように設定
systemctl enable nginx

#nginxを起動
systemctl start nginx

これでひとまずnginxのインストールは完了!

2:最新のphpをインストールする

僕はphp大好き人間なのでphp使います。

#root権限で以下の作業を実行する
sudo -s

#aptの一覧にphpを追加する
add-apt-repository ppa:ondrej/php

#aptの一覧の更新
apt-get update

#aptの一覧からphpの最新のバージョンを確認(今回は7.3だった)
apt list|grep -i mariadb-server

#phpをaptでインストール
apt-get install php7.3 php7.3-fpm php7.3-mysql php7.3-mbstring php7.3-zip

#phpの設定ファイルを編集する(その1)
vi /etc/php/7.2/cli/php.ini
→ cgi.fix_pathinfo の値を 0 に
→ date.timezone の値を "Asia/Tokyo"#phpの設定ファイルを編集する(その2)
sudo /etc/php/7.2/fpm/php.ini 
→ cgi.fix_pathinfo の値を 0 に
→ date.timezone の値を "Asia/Tokyo"

これでphpもとりあえずインストール完了!

3:nginxとphpを設定する

nginxとphpの設定を弄ってちゃんと動くようにします。

#root権限で以下の作業を実行する
sudo -s

#nginxの設定ファイルを以下を参考に編集する
vi /etc/nginx/conf.d/default.conf

- - - - -

location / {
  root   /usr/share/nginx/html;
  index  index.html index.htm;
}

  ↓

location / {
  root /usr/share/nginx/html;
  index index.html index.htm index.php;
}

- - - - -
- - - - -

#location ~ \.php$ {
#  root           html;
#  fastcgi_pass   127.0.0.1:9000;
#  fastcgi_index  index.php;
#  fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
#  include        fastcgi_params;
#}

  ↓

location ~ \.php$ {
  root /usr/share/nginx/html;
  fastcgi_pass unix:/run/php/php7.2-fpm.sock;
  fastcgi_index index.php;
  fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  include fastcgi_params;
}

- - - - -
- - - - -

#location ~ /\.ht {
#  deny  all;
#}

  ↓

location ~ /\.ht {
  deny all;
}

- - - - -

#phpの設定ファイルを編集する
/etc/php/7.3/fpm/pool.d/www.conf
→ user の値を nginx に
→ group の値を nginx に
→ listen.owner の値を nginx に
→ listen.group の値を nginx に

#サーバー起動時にphpも起動するように設定
systemctl enable php7.3-fpm

#phpを再起動
systemctl restart php7.3-fpm

#nginxを再起動
systemctl restart nginx

#nginxグループにユーザーを加入させる
usermod -aG nginx ユーザー名

#ドキュメントルートの所有者を変更する
chown -R nginx:nginx /usr/share/nginx/html/

#ドキュメントルートの権限を変更する
chmod -R 755 /usr/share/nginx/html/

ここまでやればwebは動く。

…ハズ。
大体設定を変に弄っちゃってエラー吐くパターンが多いです。
僕もかれこれ6時間くらいはハマりました、めげずにがんばりましょう!!

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

初心者がkonohaでVPSを借りてnginxでphpページを公開するまで -nginxとphp編-

nginxとphpをインストールして動かす

1:最新のnginxをインストールする

今回はapacheではなくてnginxでサーバーを立てようと思います。

#root権限で以下の作業を実行する
sudo -s

#nginx 公式サイトからPGPkeyをダウンロード
wget https://nginx.org/keys/nginx_signing.key

#PGPkeyを登録
apt-key add nginx_signing.key

#aptのリストに追記する
vi /etc/apt/sources.list
→ deb http://nginx.org/packages/ubuntu/ bionic nginx
→ deb-src http://nginx.org/packages/ubuntu/ bionic nginx

#aptのリストを更新
apt update

#nginxをaptでインストール
apt install nginx

#サーバー起動時にnginxも起動するように設定
systemctl enable nginx

#nginxを起動
systemctl start nginx

これでひとまずnginxのインストールは完了!

2:最新のphpをインストールする

僕はphp大好き人間なのでphp使います。

#root権限で以下の作業を実行する
sudo -s

#aptの一覧にphpを追加する
add-apt-repository ppa:ondrej/php

#aptの一覧の更新
apt-get update

#aptの一覧からphpの最新のバージョンを確認(今回は7.3だった)
apt list|grep -i mariadb-server

#phpをaptでインストール
apt-get install php7.3 php7.3-fpm php7.3-mysql php7.3-mbstring php7.3-zip

#phpの設定ファイルを編集する(その1)
vi /etc/php/7.2/cli/php.ini
→ cgi.fix_pathinfo の値を 0 に
→ date.timezone の値を "Asia/Tokyo"#phpの設定ファイルを編集する(その2)
sudo /etc/php/7.2/fpm/php.ini 
→ cgi.fix_pathinfo の値を 0 に
→ date.timezone の値を "Asia/Tokyo"

これでphpもとりあえずインストール完了!

3:nginxとphpを設定する

nginxとphpの設定を弄ってちゃんと動くようにします。

#root権限で以下の作業を実行する
sudo -s

#nginxの設定ファイルを以下を参考に編集する
vi /etc/nginx/conf.d/default.conf

- - - - -

location / {
  root   /usr/share/nginx/html;
  index  index.html index.htm;
}

  ↓

location / {
  root /usr/share/nginx/html;
  index index.html index.htm index.php;
}

- - - - -
- - - - -

#location ~ \.php$ {
#  root           html;
#  fastcgi_pass   127.0.0.1:9000;
#  fastcgi_index  index.php;
#  fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
#  include        fastcgi_params;
#}

  ↓

location ~ \.php$ {
  root /usr/share/nginx/html;
  fastcgi_pass unix:/run/php/php7.2-fpm.sock;
  fastcgi_index index.php;
  fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  include fastcgi_params;
}

- - - - -
- - - - -

#location ~ /\.ht {
#  deny  all;
#}

  ↓

location ~ /\.ht {
  deny all;
}

- - - - -

#phpの設定ファイルを編集する
/etc/php/7.3/fpm/pool.d/www.conf
→ user の値を nginx に
→ group の値を nginx に
→ listen.owner の値を nginx に
→ listen.group の値を nginx に

#サーバー起動時にphpも起動するように設定
systemctl enable php7.3-fpm

#phpを再起動
systemctl restart php7.3-fpm

#nginxを再起動
systemctl restart nginx

#nginxグループにユーザーを加入させる
usermod -aG nginx ユーザー名

#ドキュメントルートの所有者を変更する
chown -R nginx:nginx /usr/share/nginx/html/

#ドキュメントルートの権限を変更する
chmod -R 755 /usr/share/nginx/html/

ここまでやればwebは動く。

…ハズ。
大体設定を変に弄っちゃってエラー吐くパターンが多いです。
僕もかれこれ6時間くらいはハマりました、めげずにがんばりましょう!!

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

【CodeIgniter】form_openの使い方

Codeigniter のform_openの使い方をまとめていきます。

まず最初に、ヘルパーのロードを行います。
下記のコードでフォームヘルパーをロードします。

helper_load.php
$this->load->helper('form');

余談ですが、Codeigniter のフォームヘルパー関数の多くはフォーム値を自動的にエスケープしてくれるので、セキュリティ面でも安心です。

ヘルパーをロードしたのでform_open関数を使用できます。

form_open.php
form_open([$action = ''[, $attributes = ''[, $hidden = array()]]])

引数を1つずつ解説していきます。

$action (string):フォームの actionもしくはtarget になるURLを指定します。
この時に注意することが、CodeigniterのURLはセグメントベースのアプローチを使用していることです。
例を以下に示します。

example.com/class/function/ID

最初のセグメント(class)は呼び出されるコントローラをクラスを表します。

第2セグメント(function)は呼び出されるメソッドを表します。

第3セグメント(ID)はコントローラに渡されるID、もしくは何かの変数を表します。ちなみに第3セグメントは任意です。

例えば第3セグメントにDBから取得したIDなどを埋め込むことで、任意のレコードを表示させることができます。

簡単な使用例を以下に示します。

example_form_open.php
echo form_open('data/send');

このとき、dataは呼び出されるコントローラクラスを表し、sendは呼び出されるメソッドを表します。

また、この例では以下のようなformタグを生成します。

example_form_open.html
<form method="post" accept-charset="utf-8" action="http://example.com/index.php/ data /send">

ちなみに絶対パスでも書けなくはないですが、環境が変わると全てのURLを書き直す必要が出てきます。
しかし、セグメントベースで書けばコントローラとメソッドのみでURLが記述できるので、その必要がありません。

$attributes (array):属性を追加できます。ちなみに任意です。
次のように連想配列を渡すことで、属性を追加できます。

example_form_open.php
$attributes = array('class' => 'data', 'id' => 'userform');
echo form_open('data/send', $attributes);

こうすることで、formタグにclass属性、id属性も設定された状態で出力されます。
ちなみに以下のようなformタグを生成します。

example_form_open.html
<form method="post" accept-charset="utf-8" action="http://example.com/index.php/ data /send" class=" data " id=" userform ">

$hidden (array) :隠しフィールドを任意で追加します。
隠しフィールドとは画面上には表示せずにuserから入力されない状態にして、特定の値を送信する時に用います。
例えば2段階認証で確認ページにデータを送りたい場合、データを隠しフィールドに格納してプログラムにデータを渡す場合とかです。

次のように、連想配列を渡すことで、 隠しフィールドを追加できます。

example_form_open.php
$hidden = array('username' => 'Tom', 'member_id' => '12');
echo form_open(' data /send', '', $hidden);

この場合、以下のようなformタグを生成します。

example_form_open.html
<form method="post" accept-charset="utf-8" action="http://example.com/index.php/ data /send">
        <input type="hidden" name="username" value=" Tom " />
        <input type="hidden" name="member_id" value="12" />

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

PHP_CodeSniffierのインストール、使い方

環境

CentOS 7.5
composer 1.7.2
PHP 7.2
Laravel 5.7.11

インストール

$ composer require --dev "squizlabs/php_codesniffer=*"

devオプションで開発環境でのみインストールするようにする。packagistの記載ではglobalオプションをつけているが、プロジェクトのみで使用するためつけていない。

インストールが完了すると、codesnifferを使用できるようになるので、ヘルプを表示してみる。

$ cd プロジェクトフォルダパス
$ ./vendor/bin/phpcs -h
Usage: phpcs [-nwlsaepqvi] [-d key[=value]] [--colors] [--no-colors]
  [--cache[=<cacheFile>]] [--no-cache] [--tab-width=<tabWidth>]
  [--report=<report>] [--report-file=<reportFile>] [--report-<report>=<reportFile>]

以下省略

使い方

デフォルトで使用可能なコーディング規約を確認

$ ./vendor/bin/phpcs -i
The installed coding standards are MySource, PEAR, PSR1, PSR12, PSR2, Squiz and Zend

プロジェクトのルートディレクトリ直下にphpcs.xmlを作成(これがルールファイルになる)。以下はPSR-1とPSR-2の規約をチェックするルールファイル。プロジェクト直下のnode_modules, storage, vendorディレクトリはチェック対象外とする。

<?xml version="1.0"?>
<ruleset name="Custom Standard">
    <rule ref="PSR2">
        <!-- "PSR2" の中で除外するルールがあれば記載 -->
        <!--<exclude name="Generic.Files.LineLength"/>-->
        <!--<exclude name="PSR1.Classes.ClassDeclaration"/>-->
    </rule>
    <!-- 追加するルールがあれば記載 -->
    <!--<rule ref="PEAR.WhiteSpace.ObjectOperatorIndent"/>-->
    <!-- 除外するファイル・ディレクトリ -->
    <exclude-pattern>node_modules/</exclude-pattern>
    <exclude-pattern>storage/</exclude-pattern>
    <exclude-pattern>vendor/</exclude-pattern>
</ruleset>

設定したチェックルールの一覧を確認する。

$ ./vendor/bin/phpcs -e
The PSR2 Rule Set standard contains 42 sniffs

Generic (12 sniffs)
-------------------
  Generic.ControlStructures.InlineControlStructure
  Generic.Files.ByteOrderMark
  Generic.Files.LineEndings

以下省略

各ルールとチェックしている規約の内容はこちらを参考にさせていただきました。
PHP CodeSnifferにおけるPSR1,2の検知箇所と対応するSniffer

phpcs.xmlではルールとしてPSR2のみを指定したが、チェックするルール自体は以下ファイルに記載されており、この中にPSR-1が記載されているので、PSR-1とPSR-2の両方がチェックされる事が分かる。
src/Standards/PSR2/ruleset.xml

ファイル別に結果を出力

$ ./vendor/bin/phpcs --report=summary .
PHP CODE SNIFFER REPORT SUMMARY
---------------------------------------------------------------------------------------
FILE                                                             ERRORS  WARNINGS
---------------------------------------------------------------------------------------
/var/www/html/app/Http/Controllers/Admin/Test1Controller.php     0       2
/var/www/html/app/Http/Controllers/Admin/Test2Controller.php     6       2
/var/www/html/app/Http/Controllers/Admin/Test3Controller.php     0       2
/var/www/html/app/Http/Controllers/Admin/Test4Controller.php     7       7
/var/www/html/app/Http/Controllers/Admin/Test5Controller.php     0       6
---------------------------------------------------------------------------------------
A TOTAL OF 13 ERRORS AND 19 WARNINGS WERE FOUND IN 5 FILES
---------------------------------------------------------------------------------------
PHPCBF CAN FIX 13 OF THESE SNIFF VIOLATIONS AUTOMATICALLY
---------------------------------------------------------------------------------------

ルール別に結果を出力

$ ./vendor/bin/phpcs --report=source /path/to/code
PHP CODE SNIFFER VIOLATION SOURCE SUMMARY
-------------------------------------------------------------------------------------------
    STANDARD  CATEGORY            SNIFF                                               COUNT
-------------------------------------------------------------------------------------------
[ ] Generic   Files               Line length too long                                19
[x] PSR2      Methods             Function call signature multiple arguments          4
[x] PSR2      Methods             Function call signature content after open bracket  3
[x] PSR2      Methods             Function call signature close bracket line          2
[x] PSR2      Methods             Function call signature indent                      2
[x] Squiz     Control structures  Control signature space after close parenthesis     1
[x] Squiz     Control structures  Control signature space after keyword               1
-------------------------------------------------------------------------------------------
A TOTAL OF 32 SNIFF VIOLATIONS WERE FOUND IN 7 SOURCES
-------------------------------------------------------------------------------------------
PHPCBF CAN FIX THE 6 MARKED SOURCES AUTOMATICALLY (13 VIOLATIONS IN TOTAL)
-------------------------------------------------------------------------------------------

結果レポートをファイルとして出力。
プロジェクトフォルダ直下のresult以下にtest_phpcs.xmlファイルが作成される。

$ ./vendor/bin/phpcs --report=checkstyle --report-file=result/test_phpcs.xml .
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHP_CodeSniffierのインストールと使い方

環境

CentOS 7.5
composer 1.7.2
PHP 7.2
Laravel 5.7.11

インストール

$ composer require --dev "squizlabs/php_codesniffer=*"

devオプションで開発環境でのみインストールするようにしている。packagistの記載ではglobalオプションをつけているが、composerのホームディレクトリにインストールしない場合は不要。

インストールが完了すると、codesnifferを使用できるようになるので、ヘルプを表示してみる。

$ cd プロジェクトフォルダパス
$ ./vendor/bin/phpcs -h
Usage: phpcs [-nwlsaepqvi] [-d key[=value]] [--colors] [--no-colors]
  [--cache[=<cacheFile>]] [--no-cache] [--tab-width=<tabWidth>]
  [--report=<report>] [--report-file=<reportFile>] [--report-<report>=<reportFile>]

以下省略

使い方

デフォルトで使用可能なコーディング規約を確認

$ ./vendor/bin/phpcs -i
The installed coding standards are MySource, PEAR, PSR1, PSR12, PSR2, Squiz and Zend

プロジェクトのルートディレクトリ直下にphpcs.xmlを作成(これがルールファイルになる)。以下はPSR-1とPSR-2の規約をチェックするルールファイル。プロジェクト直下のnode_modules, storage, vendorディレクトリはチェック対象外とする。

<?xml version="1.0"?>
<ruleset name="Custom Standard">
    <rule ref="PSR2">
        <!-- "PSR2" の中で除外するルールがあれば記載 -->
        <!--<exclude name="Generic.Files.LineLength"/>-->
        <!--<exclude name="PSR1.Classes.ClassDeclaration"/>-->
    </rule>
    <!-- 追加するルールがあれば記載 -->
    <!--<rule ref="PEAR.WhiteSpace.ObjectOperatorIndent"/>-->
    <!-- 除外するファイル・ディレクトリ -->
    <exclude-pattern>node_modules/</exclude-pattern>
    <exclude-pattern>storage/</exclude-pattern>
    <exclude-pattern>vendor/</exclude-pattern>
</ruleset>

設定したチェックルールの一覧を確認する。

$ ./vendor/bin/phpcs -e
The PSR2 Rule Set standard contains 42 sniffs

Generic (12 sniffs)
-------------------
  Generic.ControlStructures.InlineControlStructure
  Generic.Files.ByteOrderMark
  Generic.Files.LineEndings

以下省略

各ルールとチェックしている規約の内容はこちらを参考にさせていただきました。
PHP CodeSnifferにおけるPSR1,2の検知箇所と対応するSniffer

phpcs.xmlではルールとしてPSR2のみを指定したが、チェックするルール自体は以下ファイルに記載されており、この中にPSR-1が記載されているので、PSR-1とPSR-2の両方がチェックされる事が分かる。
src/Standards/PSR2/ruleset.xml

ファイル別に結果を出力

$ ./vendor/bin/phpcs --report=summary .
PHP CODE SNIFFER REPORT SUMMARY
---------------------------------------------------------------------------------------
FILE                                                             ERRORS  WARNINGS
---------------------------------------------------------------------------------------
/var/www/html/app/Http/Controllers/Admin/Test1Controller.php     0       2
/var/www/html/app/Http/Controllers/Admin/Test2Controller.php     6       2
/var/www/html/app/Http/Controllers/Admin/Test3Controller.php     0       2
/var/www/html/app/Http/Controllers/Admin/Test4Controller.php     7       7
/var/www/html/app/Http/Controllers/Admin/Test5Controller.php     0       6
---------------------------------------------------------------------------------------
A TOTAL OF 13 ERRORS AND 19 WARNINGS WERE FOUND IN 5 FILES
---------------------------------------------------------------------------------------
PHPCBF CAN FIX 13 OF THESE SNIFF VIOLATIONS AUTOMATICALLY
---------------------------------------------------------------------------------------

ルール別に結果を出力

$ ./vendor/bin/phpcs --report=source /path/to/code
PHP CODE SNIFFER VIOLATION SOURCE SUMMARY
-------------------------------------------------------------------------------------------
    STANDARD  CATEGORY            SNIFF                                               COUNT
-------------------------------------------------------------------------------------------
[ ] Generic   Files               Line length too long                                19
[x] PSR2      Methods             Function call signature multiple arguments          4
[x] PSR2      Methods             Function call signature content after open bracket  3
[x] PSR2      Methods             Function call signature close bracket line          2
[x] PSR2      Methods             Function call signature indent                      2
[x] Squiz     Control structures  Control signature space after close parenthesis     1
[x] Squiz     Control structures  Control signature space after keyword               1
-------------------------------------------------------------------------------------------
A TOTAL OF 32 SNIFF VIOLATIONS WERE FOUND IN 7 SOURCES
-------------------------------------------------------------------------------------------
PHPCBF CAN FIX THE 6 MARKED SOURCES AUTOMATICALLY (13 VIOLATIONS IN TOTAL)
-------------------------------------------------------------------------------------------

結果レポートをファイルとして出力。
プロジェクトフォルダ直下のresult以下にtest_phpcs.xmlファイルが作成される。

$ ./vendor/bin/phpcs --report=checkstyle --report-file=result/test_phpcs.xml .

■参考にさせていただきました
新標準PSRに学ぶきれいなPHP
https://www.slideshare.net/yandod/psrphp

PSR-1 基本コーディング規約(日本語)
http://www.infiniteloop.co.jp/docs/psr/psr-1-basic-coding-standard.html

PSR-2 コーディングガイド(日本語)
http://www.infiniteloop.co.jp/docs/psr/psr-2-coding-style-guide.html

PHP PSR一覧 2017年版
https://qiita.com/rana_kualu/items/f41d8f657df7709bda0f

PHP CodeSnifferにおけるPSR1,2の検知箇所と対応するSniffer
https://qiita.com/piotzkhider/items/c90dd9253e9822fab3a2

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

さくらサーバー PDOがSQLSTATE[HY000] [2002] No such file or directory

いろいろ調べたけど下記を修正するだけで通った。

define('PDO_DSN','mysql:dbhost=localhost;dbname=' . DB_DATABASE);

define('PDO_DSN','mysql:host=localhost;dbname=' . DB_DATABASE);

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

【Laravel】GItLab CIでユニットテストを自動実行+カバレッジを出力してGitLab Pagesにホスティングする

自前で運用しているGitLab CE(Community Edition)で、Pipelineを利用して
LaravelアプリケーションのPHP Unitを自動で回す設定を作成した時のメモ

PHP Unit設定

PHP Unitを実行した際に、カバレッジのデータがHTMLとして出力されるように、以下の設定を行う

phpunit.xml
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         bootstrap="vendor/autoload.php"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false">
... 省略

+    <logging>
+        <log type="coverage-clover" target="public/coverage/logs/clover.xml"/>
+        <log type="coverage-html" target="public/coverage"/>
+    </logging>
</phpunit>

GitLab CI設定

Gitリポジトリのルート配下に.gitlab-ci.ymlを作成する。

.gitlab-ci.yml
# composerによって生成されるvendor配下をキャッシュする
cache:
  key: ${CI_COMMIT_REF_SLUG}
  paths:
    - vendor/

# Build and Test
php-7.2: &build
  image: php:7.2-cli-alpine
  variables:
    COMPOSER_VERSION: 1.8.6
  script:
    # 必要なライブラリをインストール
    - apk add git autoconf build-base
    - pecl install xdebug
    - docker-php-ext-install mysqli pdo pdo_mysql
    - docker-php-ext-enable xdebug
    - curl https://getcomposer.org/download/${COMPOSER_VERSION}/composer.phar > composer.phar
    - php composer.phar install
    # .envの作成
    - cp .env.example .env
    # ユニットテストの実行
    - vendor/bin/phpunit --configuration phpunit.xml --coverage-text --colors=never
  artifacts:
    paths:
      # 生成したカバレッジレポートを、次のjobで利用する
      - public/coverage

# 異なるPHPのバージョンを指定してジョブを回したい場合、
# 以下のように`build`アンカーを呼び出したうえで、別のalpineのimageを指定すればOK
php-7.1:
  <<: *build
  image: php:7.1-cli-alpine
  # 以下のようにすれば、composerのバージョンを指定できる
  variables:
    COMPOSER_VERSION: 1.6.5

# Unitテストのカバレッジを、Gitlab Pagesにホスティングする
pages:
  stage: deploy
  extends: php-7.2
  artifacts:
    paths:
      - public
  only:
    - develop

これで、GitLabのリモートリポジトリにgit pushすると自動でテストが走る。
以下のURLにアクセスすると、HTML出力したユニットテストのカバレッジが確認できる。
http://{GitLabドメイン}/{プロジェクト名}/coverage/

参考サイト

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

GItLab CIでユニットテストを自動実行+カバレッジを出力してGitLab Pagesにホスティングする

自前で運用しているGitLab CE(Community Edition)で、Pipelineを利用して
LaravelアプリケーションのPHP Unitを自動で回す設定を作成した時のメモ

PHP Unit設定

PHP Unitを実行した際に、カバレッジのデータがHTMLとして出力されるように、以下の設定を行う

phpunit.xml
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         bootstrap="vendor/autoload.php"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false">
... 省略

+    <logging>
+        <log type="coverage-clover" target="public/coverage/logs/clover.xml"/>
+        <log type="coverage-html" target="public/coverage"/>
+    </logging>
</phpunit>

GitLab CI設定

Gitリポジトリのルート配下に.gitlab-ci.ymlを作成する。

.gitlab-ci.yml
# composerによって生成されるvendor配下をキャッシュする
cache:
  key: ${CI_COMMIT_REF_SLUG}
  paths:
    - vendor/

# Build and Test
php-7.2: &build
  image: php:7.2-cli-alpine
  variables:
    COMPOSER_VERSION: 1.8.6
  script:
    # 必要なライブラリをインストール
    - apk add git autoconf build-base
    - pecl install xdebug
    - docker-php-ext-install mysqli pdo pdo_mysql
    - docker-php-ext-enable xdebug
    - curl https://getcomposer.org/download/${COMPOSER_VERSION}/composer.phar > composer.phar
    - php composer.phar install
    # .envの作成
    - cp .env.example .env
    # ユニットテストの実行
    - vendor/bin/phpunit --configuration phpunit.xml --coverage-text --colors=never
  artifacts:
    paths:
      # 生成したカバレッジレポートを、次のjobで利用する
      - public/coverage

# 異なるPHPのバージョンを指定してジョブを回したい場合、
# 以下のように`build`アンカーを呼び出したうえで、別のalpineのimageを指定すればOK
php-7.1:
  <<: *build
  image: php:7.1-cli-alpine
  # 以下のようにすれば、composerのバージョンを指定できる
  variables:
    COMPOSER_VERSION: 1.6.5

# Unitテストのカバレッジを、Gitlab Pagesにホスティングする
pages:
  stage: deploy
  extends: php-7.2
  artifacts:
    paths:
      - public
  only:
    - develop

これで、GitLabのリモートリポジトリにgit pushすると自動でテストが走る。
以下のURLにアクセスすると、HTML出力したユニットテストのカバレッジが確認できる。
http://{GitLabドメイン}/{プロジェクト名}/coverage/

参考サイト

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

php-master-changes 2019-06-24

今日はテストの修正があった!

2019-06-24

cmb69: Split test case

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

マイグレーションについて

前職で、「マイグレーションについて調べてみて。」と言われたけど、結局何を調べて答えたのか忘れてメモもしてなくて。改めて調べてみました。

 ↑キーワード検索から、いろんな人の記事を漁るのも良い方法かもしれません。

Migration とは何者か

【現時点での理解】
  複数人で開発していて、データベースが勝手に書き換えられるような環境での開発で、
 全員がおんなじ状態のDBを使えるようにする仕組み。

 ソースコードに対するバージョンコントローラの Git 、
 データベースに対するバージョンコントローラの Migration

 みたいなものでしょうか。
 ※筆者は主に PHP/Laravel を書きます。

 teratailでの質問

PHP/Laravel の場合

 Laravelドキュメント:マイグレーション
 bz0さんの記事

Ruby on Rails の場合

 sntkazuさんの記事
 wacker8818さんの記事

Python/Django の場合

 okoppe8さんの記事

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

PHPで何かつくる!

本稿は、筆者のアイデアノートとなります。
書き始めて、それぞれ形になったら、別記事としてUPしていきます。
別記事で書いてる物をPHPでも実装してみることになると予想。

目的

  • PHPと仲良くなる。
  • Laravel 以外のフレームワークに積極的に触れる。

作りたいもの

  • Webスクレイピングサイト
  • パスワード暗号化提案サイト
  • 自宅監視システム(虫検知)
    • Raspberry Pi と カメラモジュール
    • 虫判定 = Tensorflow をこねこねする

参考

初めてのPHP

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

ライブラリを使わずにTwitter APIでダイレクトメッセージを送信する [PHP]

TwitterのAPIを利用して、任意のユーザーへダイレクトメッセージを送信するPHPのコードです。ライブラリは使わずに直接実装するケースを想定しています。

前提条件

・送信元のアカウントでAPIを利用出来る。(Twitter Developersに登録済み)
・送信相手のユーザーIDが判明している。
送信相手がこちら(送信元)のアカウントをフォローしている。

処理の流れ

  1. 署名キーを作る
  2. HTTPヘッダ用のパラメータを作る
  3. パラメータ(2.)をソートする
  4. 署名キー(1.)とパラメータ(3.)から署名を作る
  5. パラメータ(3.)に署名(4.)を追加する
  6. パラメータ(3.)からHTTPヘッダ用の配列を作る
  7. POSTデータ用の配列を作る
  8. cURLでエンドポイントにデータを投げる
  9. エンドポイントの応答を受け取る

接続先(エンドポイント)

https://api.twitter.com/1.1/direct_messages/events/new.json

処理に必要な値

Twitter Developersで下記の値を予め取得しておく必要があります。

$api_key = 'APIキー';
$api_secret = 'APIシークレット';
$access_token = 'アクセストークン';
$access_token_secret = 'アクセストークンシークレット';

1. 署名キーを作る

APIシークレットとアクセストークンシークレットを用いて署名キーを作成します。

$signature_key = rawurlencode( $api_secret )."&".rawurlencode( $access_token_secret );

2. HTTPヘッダ用のパラメータを作る

エンドポイントへ渡すための認証データを連想配列で作成します。

$paramData = array(
  "oauth_token" => rawurlencode( $access_token ),
  "oauth_consumer_key" => rawurlencode( $api_key ),
  "oauth_signature_method" => rawurlencode( "HMAC-SHA1" ),
  "oauth_timestamp" => time(),
  "oauth_nonce" => microtime(),
  "oauth_version" => rawurlencode( "1.0" )
);

3. パラメータをソートする

ksortで連想配列をソートします。これを忘れると認証エラーが起き得ます。

ksort( $paramData );

4. 署名キーとパラメータから署名を作る

1で作成した署名キーと、2で作成したパラメータの配列を利用して、署名を作ります。

$sig_param = rawurlencode('POST')."&".
  rawurlencode('https://api.twitter.com/1.1/direct_messages/events/new.json')."&".
  rawurlencode( http_build_query( $paramData , "", "&" ) );

$signature = hash_hmac( "sha1", $sig_param, $signature_key, TRUE );
$signature = base64_encode( $signature );

5. パラメータに署名を追加する

連想配列に署名を追加します。

$paramData['oauth_signature'] = $signature;

6. パラメータからHTTPヘッダ用の配列を作る

cURLで使うための配列を新たに作成しておきます。

$httpHeader = array(
  'Authorization: OAuth '.http_build_query( $paramData, "", "," ),
  'content-type: application/json'
);

7. POSTデータ用の配列を作る

cURLで送信するボディにあたるデータを作成します。これは後にjsonエンコードします。
ここで送信先のユーザーIDと、送信したいメッセージもセットします。

$postData = array(
  "event" => array(
    "type" => "message_create",
    "message_create" => array(
      "target" => array(
        "recipient_id" => '送信先のユーザID'  //送信先ID
      ),
      "message_data" => array(
        "text" => '送信メッセージ'  //送信したいメッセージ
      )
    )
  )
);

Eventオブジェクトの中に入れ子で情報を詰め込んでいます。
上記のサンプルコードは必須項目のみを記述していますが、message_dataオブジェクト(メッセージが入っているところ)にはオプションも追記可能です。

詳しくはTwitter公式のAPIリファレンスを確認してください。1

8. cURLでエンドポイントにデータを投げる

これまでに作成した各種配列をセットして、cURLでエンドポイントへデータを渡します。

$ch = curl_init();

curl_setopt($ch, CURLOPT_HTTPHEADER, $httpHeader);
curl_setopt($ch, CURLOPT_URL, 'https://api.twitter.com/1.1/direct_messages/events/new.json');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, rawurlencode('POST'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode( $postData ));

$json = curl_exec($ch);

curl_close($ch);

9. エンドポイントの応答を受け取る

ダイレクトメッセージの送信に成功すると、message_createイベントのIDやタイムスタンプを含んだjsonデータが返されます。ここでjsonデータを連想配列へ変換しておきます。

$response = json_decode( $json, true );

echo var_dump( $response );

var_dumpした結果が下記です。

array(1) {
  ["event"]=> array(4) {
    ["type"]=> string(14) "message_create"
    ["id"]=> string(19) "イベントID"
    ["created_timestamp"]=> string(13) "1561275503817"  //ミリ秒
    ["message_create"]=> array(3) {
      ["target"]=> array(1) {
        ["recipient_id"]=> string(10) "送信先のID"
      }
      ["sender_id"]=> string(19) "送信元のID"
      ["message_data"]=> array(2) {
        ["text"]=> string(24) "送信メッセージ"
        ["entities"]=> array(4) {
          ["hashtags"]=> array(0) { }
          ["symbols"]=> array(0) { }
          ["user_mentions"]=> array(0) { }
          ["urls"]=> array(0) { }
        }
      }
    }
  }
}

これ以降の処理は、idが含まれているか、などの条件で処理判定すればよいかと思います。

if( empty( $response['event']['id'] ) ){
  //失敗時の処理
} else {
  //成功時の処理
}

尚、レスポンスデータに含まれるタイムスタンプはミリ秒で返ってきます。2
そのままでは日付表示が出来ないので、秒に変換する必要があります。

$timestamp = $response['event']['created_timestamp'];
echo date('Y-m-d H:i:s', ( $timestamp / 1000 )); //1000で割って秒にする

結果
2019-06-24 06:42:31

最後に

Qiitaに登録して初めて書く記事となります。コードや文章に稚拙な部分があるかもしれませんが、ご容赦ください。可読性を優先してわざと定数化していない箇所はあります。

誤りのご指摘やご意見などがありましたら、是非お願いいたします。

注釈(参考サイト)

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

PHPのバージョンアップグレード方法

はじめに

PHPのバージョンを上げる際、色々やりすぎて訳わからなくなって他ので思考整理のため、備忘録としてまとめました。
今回はPHP7.2x系から7.3x系へのバージョンアップを行います。

手順

現在のバージョンを確認します。

$ php -v
PHP 7.2.19 (cli) (built: Jun 17 2019 09:03:55) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.19, Copyright (c) 1999-2018, by Zend Technologies

PHP7.2x系になってることが確認できました。
brew searchコマンドでbrew installできるphpのバージョンを確認できます。
(今回はphp7系で探してみます。)

$ brew search php@7
==> Formulae
php@7.1                            php@7.2 ✔                          php@7.3

上記のように表示されるはずです。
自分はphp@7.2は既にインストール済みなので右にチェックマークがついてます。
ではphp@7.3をインストールしましょう。

$ brew install php@7.3
==> Downloading https://homebrew.bintray.com/bottles/php-7.3.6_1.mojave.bottle.tar.gz
Already downloaded: /Users/KazukiSaito/Library/Caches/Homebrew/downloads/d1adefd1f87d0e00b888bf32e0a29a1e0e0ee885ff3508c2e46ce1ad7f1711d9--php-7.3.6_1.mojave.bottle.tar.gz
==> Pouring php-7.3.6_1.mojave.bottle.tar.gz
==> /usr/local/Cellar/php/7.3.6_1/bin/pear config-set php_ini /usr/local/etc/php/7.3/php.ini system
==> /usr/local/Cellar/php/7.3.6_1/bin/pear config-set php_dir /usr/local/share/pear system
==> /usr/local/Cellar/php/7.3.6_1/bin/pear config-set doc_dir /usr/local/share/pear/doc system
==> /usr/local/Cellar/php/7.3.6_1/bin/pear config-set ext_dir /usr/local/lib/php/pecl/20180731 system
==> /usr/local/Cellar/php/7.3.6_1/bin/pear config-set bin_dir /usr/local/opt/php/bin system
==> /usr/local/Cellar/php/7.3.6_1/bin/pear config-set data_dir /usr/local/share/pear/data system
==> /usr/local/Cellar/php/7.3.6_1/bin/pear config-set cfg_dir /usr/local/share/pear/cfg system
==> /usr/local/Cellar/php/7.3.6_1/bin/pear config-set www_dir /usr/local/share/pear/htdocs system
==> /usr/local/Cellar/php/7.3.6_1/bin/pear config-set man_dir /usr/local/share/man system
==> /usr/local/Cellar/php/7.3.6_1/bin/pear config-set test_dir /usr/local/share/pear/test system
==> /usr/local/Cellar/php/7.3.6_1/bin/pear config-set php_bin /usr/local/opt/php/bin/php system
==> /usr/local/Cellar/php/7.3.6_1/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.3/

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.3.6_1: 521 files, 77.0MB
$

これでインストールできたはずです。
(先ほどのphp searchコマンドで確認したらphp@7.3の横にもチェックマークがついてるのが確認できるはずです。)

PHPの環境PATHを通します。
現在のPATHを確認します。(ちなみにこの時点でバージョンは変わってないはずです。)

$ which php
/usr/local/opt/php@7.2/bin/php

上記のようになってますね。

以下の7.2を7.3に変えるだけです。

$ vi .bash_profile
- export PATH="$PATH:/usr/local/opt/php@7.2/bin"
+ export PATH="$PATH:/usr/local/opt/php@7.3/bin"

再度バージョンを確認します。

$ php -v
PHP 7.3.6 (cli) (built: Jun 17 2019 08:40:34) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.6, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.3.6, Copyright (c) 1999-2018, by Zend Technologies

反映されてますね。

ちなみにPHPの環境PATHの方も確認してみます。

$ which php
/usr/local/opt/php@7.3/bin/php

PATHの方も反映されてますね。

これで終わりです。

まとめ

①brew installでアップグレードしたいバージョンのPHPを取得する。
②環境PATHを通す。

Homebrewを使ってPHPのバージョンをアップグレードしたい時は上記2点のポイントを抑えておけば今後のバージョンアップグレードは困らないと思います。
(やったことないので分からないけど多分、ダウングレードも同じ要領で行けるのかな・・・、ここについては自信ないです。)

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

私がプログラミングスクールにいく理由

大学4年生法学部の学生です!
私がなぜ4年生になってプログラミングスクールに行こうと思ったのかを簡単に紹介したいと思います。
現在、プログラミング未経験だけど、プログラマーになりたいと思った方は是非参考にしてください。

入社するまでに周りと差をつけたいから

私は法学部ですが、学んできたことと全く関係のないIT企業にシステムエンジニアとして内定を頂いております。法学部ですので、プログラミング経験はほとんどありません。私はその状況に危機感を覚え、入社するまでにはある程度実践的なプログラミング知識を身につけておこう、そうすることで入社するまでに他の学生と差をつけようと考えプログラミングスクールに参加することを決めました。

学習の成果

実際にどのようなことを学んだのか最後に一部だけ紹介します。スクール2日目で書いた内容です。
わからないことは全てメンターに聞けるので、早く学習を進めることができました。

<?php
session_start();
if (empty($_SESSION["name"]) && empty($_SESSION["email"])){
  require('validation.php');
  validation($_POST["name"],$_POST["email"]);
}
?>
<!DOCTYPE html>
<html lang="ja" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <h4>入力内容を確認してください</h4>
    <form action="complete.php" method="POST">
      <p>氏名</p>
      <?php
        if (isset($_SESSION["name"])) {
          echo $_SESSION["name"];
        }
      ?>
      <p>メールアドレス</p>
      <?php
        if (isset($_SESSION["email"])) {
          echo $_SESSION["email"];
        }
      ?>
      <p><input type="submit" value="送信する"></p>
    </form>
    <form action="input.php" method="POST">
      <p><input type="submit" value="戻る"</p>
    </form>
  </body>
</html>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

google-api-php-clientを使ってGoogle Analyticsのデータを取得する

はじめに

Webアクセス解析ツールとして Google Analytics(以下GA)を利用しています。
自社のデータはGAから、競合他社はVALUESから、というスキームが多いのですが
それぞれ別々にデータを取得してBIツールで繋ぎ合わせる、というやり方ではなく
1つのWebサービス上でシームレスに繋ぎ合わさったサービスの開発に取り組んでいます。

データ検証として、google-api-php-clientを使ってGAデータの取得までを試したため
作成したラッパーとともに記載します。

GAデータを取得するまで

1.サービスアカウントキーの取得
2.Google Analytics APIの有効化
3.Google API Client Libraries(PHP)のインストール
4.GA側の設定
5.GAデータの取得
※ Googleアカウントは既にある前提
※ 1~3は特に順番はありません(どれを先にやってもよいです)
※ 1,3は既に他で実施済みであれば不要

1.サービスアカウントキーの取得

※既に取得済みであればこの項は不要です。

Google Developer Console または Google Cloud Platform の
APIとサービス > 認証情報
から認証情報(サービスアカウントキー)を作成します。
図1.png
※サービスアカウント名を入力すると、サービスアカウントIDが自動で振られます。
※サービスアカウントIDをメモしておきます(後で使います)
図2.png

※作成したJSONファイルを保存します(後で使います)

2.Google Analytics APIの有効化

Google Developer Console または Google Cloud Platform の
APIとサービス > ライブラリ
からGoogle Analytics APIを有効化します。
図3.png

※ Google Analytics APIは一番下の その他 の中にあります。
図4.png
※上図は既にAPIを有効にした後ですが、前であれば「有効にする」ボタンが表示されているはずです。
※ まだプロジェクトがない場合は、併せてプロジェクトも作成しておきましょう。

3.Google API Client Libraries(PHP)のインストール

※既にインストール済みであればこの項は不要です

google-api-php-clientのGitHubはこちら
google-api-php-client
Composerまたはソースコードを直接ダウンロードします。

4.GA側の設定

作成したサービスアカウントIDをGA側に設定します。

目的のビューに対してユーザー(1.で取得したサービスアカウントID)を追加します。
図5.png
図6.png
※メールアドレスにサービスアカウントIDを設定します。
図7.png
※権限は「表示と分析」のみで大丈夫です。

図8.png
※対象のビューIDをメモしておきます(あとで使います)

5.GAデータの取得

以下がサンプルコードです(PHP)

APIを使いやすいようにラッパーを用意します。

GAwrapper.php
<?php
require_once 'google-api-php-client/vendor/autoload.php';

Class GAwrapper {

    private $viewId;
    private $analytics;

    public function __construct($authKey, $viewId) {
        $this->viewId = $viewId;

        $client = new Google_Client();
        $client->setApplicationName("Analytics Reporting");
        $client->setAuthConfig($authKey);
        $client->setScopes(['https://www.googleapis.com/auth/analytics.readonly']);
        $analytics = new Google_Service_Analytics($client);

        $this->analytics = $analytics;
    }

    public function query($startDate='7daysAgo', $endDate='yesterday', $aryMetrics=array(), $aryDimensions=array(), $arySort=array(), $aryFilters=array(), $maxResults=1000) {
        // Metrics
        if (count($aryMetrics) > 0) {
            foreach ($aryMetrics as $key => $value) {
                $aryMetrics[$key] = 'ga:'.$value;
            }
            $metrics = implode(',', $aryMetrics);
        } else {
            $metrics = '';
        }
        // Dimensions
        if (count($aryDimensions) > 0) {
            foreach ($aryDimensions as $key => $value) {
                $aryDimensions[$key] = 'ga:'.$value;
            }
            $dimensions = implode(',', $aryDimensions);
        } else {
            $dimensions = '';
        }
        // Sort
        if (count($arySort) > 0) {
            foreach ($arySort as $key => $value) {
                if (strpos($value, '-') === 0) {
                    $arySort[$key] = '-ga:'.substr($value, 1);
                } else {
                    $arySort[$key] = 'ga:'.$value;
                }
            }
            $sort = implode(',', $arySort);
        } else {
            $sort = '';
        }
        // Filters
        if (count($aryFilters) > 0) {
            foreach ($aryFilters as $key => $value) {
                $aryFilters[$key] = 'ga:'.$value;
            }
            $filters = implode(';', $aryFilters);
        } else {
            $filters = '';
        }
        $optParams = array();
        if (strlen($dimensions) > 0) {
            $optParams['dimensions'] = $dimensions;
        }
        if (strlen($sort) > 0) {
            $optParams['sort'] = $sort;
        }
        if (strlen($filters) > 0) {
            $optParams['filters'] = $filters;
        }
        $optParams['max-results'] = $maxResults;
        // Excute Query
        $result = $this->analytics->data_ga->get('ga:'.$this->viewId, $startDate, $endDate, $metrics, $optParams);
        $data = array();
        foreach ($result->rows as $row) {
            $index = 0;
            $outDimensions = array();
            foreach ($aryDimensions as $dimension) {
                $value = $row[$index];
                if ($dimension == 'ga:date') {
                    $value = substr($value, 0, 4).'-'.substr($value, 4, 2).'-'.substr($value, 6, 2);
                } else if ($dimension == 'ga:isoYearIsoWeek') {
                    $value = $this->weekStartDate(substr($value, 0, 4), (int)substr($value, 4, 2), $startDate).'週';
                } else if ($dimension == 'ga:yearMonth') {
                    $value = substr($value, 0, 4).'-'.substr($value, 4, 2);
                }
                $outDimensions[str_replace('ga:', '', $dimension)] = $value;
                $index++;
            }
            $outMetrics = array();
            foreach ($aryMetrics as $value) {
                $outMetrics[str_replace('ga:', '', $value)] = $row[$index];
                $index++;
            }
            $aryOut = array();
            foreach ($outDimensions as $key => $value) {
                $aryOut[$key] = $value;
            }
            $aryOut['metrics'] = $outMetrics;
            $data[] = $aryOut;
        }
        return $data;
    }

    // 年と週番号から、その週の最初の日付文字列を得る(ISO 8601準拠)
    private function weekStartDate($year, $weekNumber=1, $startDate) {
        $time = strtotime("{$year}-01-01");
        $week = date("w", $time);
        if ($week > 4 || $week == 0) {
            $time = strtotime("next Monday", $time);
        } elseif ($week != 1) {
            $time = strtotime("last Monday", $time);
        }
        $weekNumber--;
        $retData = date("Y-m-d", strtotime("+{$weekNumber} Week", $time));
        if ($startDate > $retData) {
            $retData = $startDate;
        }
        return $retData;
    }
}

実際の取得サンプルは下記のようになります。
$authKeyに1.で取得したJSONファイルを指定します。
$viewIdに4.でメモしたビューIDを指定します。

gasample.php
<?php
/* Google Analytics API設定 */
$authKey = 'xxxxxx-9999999-xxxxxxxxxxxx.json';
$viewId  = '99999999';

/* 入力パラメータ */
if (isset($_REQUEST['startDate'])) {
    $startDate = $_REQUEST['startDate'];
} else {
    $startDate = date("Y-m-d", strtotime("-1 Month"));
}
if (isset($_REQUEST['endDate'])) {
    $endDate = $_REQUEST['endDate'];
} else {
    $endDate = date("Y-m-d", strtotime("-1 day"));
}
if (isset($_REQUEST['dateTerm'])) {
    $dateTerm = $_REQUEST['dateTerm'];
} else {
    $dateTerm = 'date';
}

/* データ取得準備 */
require_once 'GAwrapper.php';
$analytics = new GAwrapper($authKey, $viewId);

$metrics    = array();
$dimensions = array();
$sort       = array();
$filters    = array();
$maxResults = 1000;

/* ユーザー数、セッション数、PV数を取得する */
$metrics    = array('users', 'sessions', 'pageviews');
$dimensions = array($dateTerm);
$sort       = array($dateTerm);
$data = $analytics->query($startDate, $endDate, $metrics, $dimensions, $sort, $filters, $maxResults);

print_r($data);

※他のメトリックスやディメンションを指定する場合はこちらを参考にしてください。
Dimensions & Metrics Explorer | アナリティクス Reporting API v4
※ラッパーを使用する場合、ラッパーが自動的に付与するので先頭の「ga:」は不要です。

参考にしたサイト

【最新版】GoogleAnalytics API 認証設定について画像多めで説明します。 | 東京上野のWeb制作会社LIG

おわりに

プログラムを作成した時点からしばらく間が空いてしまったため、一応現在も動作しているプログラムの一部を抜粋する形で記事を起こしましたが、古い書き方の箇所があるかもしれません。
Googleさんの画面やAPIはすぐに変わってしまいがち。。。

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

自動メール送信機能の実装

ECサイトの作成において、商品の購入が確定したときに確認メールを自動で送信する機能を実装したので、その方法についてメモを残しておきます。

作りたいもの

  • 購入確定画面
  • 確定と同時に購入者のメールアドレスにメールを自動送信
  • メールには購入者氏名、配送先住所、購入した商品の種類と個数、合計金額を記載

メールを送信する関数

メールを送信するにはmb_send_mail()関数を使用します。引数は4つで

mb_send_mail(受信者のメールアドレス,件名,本文,送信者のメールアドレス)

のような形で使用します。

XAMPPでメールを送信する設定

上記の関数をXAMPP環境で使用してもmb_send_mail(): Failed to connect to mailserver at "localhost" port 25というエラーが出ると思います。
XAMPPでメールを送信するには設定が必要なのでそちらも説明します。
まず、xampp/phpにあるphp.iniを編集します。

sendmail_path = "\"C:\xampp\sendmail\sendmail.exe\" -t"

と記載されている箇所を

sendmail_path = "\"C:\xampp\sendmail\sendmail.exe\" -t"
;sendmail_path="C:\xampp\mailtodisk\mailtodisk.exe"

と変更します。php.iniの設定はこれでOKです。
次は、xampp/sendmailに入っているsendmail.iniを編集します。
まずsmtp_serverの設定をします。

smtp_server=smtp.mail.yahoo.co.jp

こうすることで、yahooメールで設定できます。
次に、以下のようにポート番号の設定をします。

smtp_port=587

auth_usernameauth_password をyahooメールのユーザ名とパスワードに設定します。

auth_username=yourusername
auth_password=yourpassword

最後にforce_senderにメールアドレスを入れて完了です。

force_sender=youraccount@yahoo.co.jp

以上の設定をすることで、メールが送れるようになります。

購入確定画面サンプル

<?php
session_start();
$name=$_POST['name'];
$adress=$_POST['adress'];
$total=$_POST['total'];
$creditNum=$_POST['creditNum'];
$status=1;
$count=count($_SESSION['cart']);
if(isset($name) && isset($adress) && isset($total) && isset($creditNum) ){

  $hostname = "localhost";    //ホスト名
  $userid = "iimori";    //データベースユーザ名
  $passwd = "A8h3avau";    //接続パスワード
  $dbname = "ecdatabase";    //データベース名
  $con=mysqli_connect($hostname,$userid,$passwd,$dbname);   //db接続に必要な情報を変数に入れる

          // 接続状況をチェックします
  if (mysqli_connect_errno()) {
      die("データベースに接続できません:" . mysqli_connect_error() . "\n");
  } else {
      echo "データベースの接続に成功しました。\n";
  }

  $con->set_charset('utf8');



  /* プリペアドステートメントを作成します */
  if ($stmt = mysqli_prepare($con, "INSERT INTO orders (name, adress, totalprice, creditNum, status) VALUES (?,?,?,?,?)")) {

      /* マーカにパラメータをバインドします */
      mysqli_stmt_bind_param($stmt, "ssssi", $name,$adress,$total,$creditNum,$status);

      /* クエリを実行します */
      mysqli_stmt_execute($stmt);


      /* 値を取得します */
      mysqli_stmt_fetch($stmt);

      /* ステートメントを閉じます */
      mysqli_stmt_close($stmt);
  }
  $query = 'SELECT id FROM orders WHERE id=(SELECT MAX(id) FROM orders)';
  $result = $con->query($query);
  // クエリを実行します。
  if (!$result) {
      echo $con->error;
      exit();
  }
  $row=$result->fetch_array(MYSQLI_ASSOC);

  for($i=0; $i<$count; $i++){
  /* プリペアドステートメントを作成します */
    if ($stmt = mysqli_prepare($con, "INSERT INTO order_detail (order_id, productName, boughtQuantity) VALUES (?,?,?)")) {

        /* マーカにパラメータをバインドします */
        mysqli_stmt_bind_param($stmt, "sss", $row['id'],$_POST['productName'][$i],$_SESSION['quantity'][$i]);

        /* クエリを実行します */
        mysqli_stmt_execute($stmt);


        /* 値を取得します */
        mysqli_stmt_fetch($stmt);

        /* ステートメントを閉じます */
        mysqli_stmt_close($stmt);
    }
  }
  // 接続を閉じます
  mysqli_close($con);

}

//送信元の設定
$header="From: me@example.com";

  // 変数とタイムゾーンを初期化
$auto_reply_subject = null;
$auto_reply_text = null;
date_default_timezone_set('Asia/Tokyo');

// 件名を設定
$auto_reply_subject = '注文が確定しました';

// 本文を設定
$auto_reply_text = "以下の注文で確定しました。\n\n";
$auto_reply_text .= "氏名:".$name. "\n";
$auto_reply_text .= "配送先:".$adress."\n";
$auto_reply_text .= "お買い上げ商品:";
for($j=0; $j<$count; $j++){
  $auto_reply_text .= $_POST['productName'][$j]." × ".$_SESSION['quantity'][$j]."個"."\n";
}
$auto_reply_text .= "お買い上げ合計金額:".$total;
// メール送信
mb_send_mail( $_POST['email'], $auto_reply_subject, $auto_reply_text, $header);

unset($_SESSION['cart']);
unset($_SESSION['quantity']);
 ?>

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>注文完了</title>
  <link rel="stylesheet" type="text/css" href="stylesheet.css">

</head>
  <body>
    <h1>注文完了</h1>


<div class="center">



  注文が確定しました。<br>
  お買い上げありがとうございます!<br>
  <form  action="product_list.php" method="post">
    <input type="submit" name="back" value="商品一覧に戻る">
  </form>

</div>

  </body>

</html>

以上が購入確定画面のソースコードになります。
$_SESSION['cart'][]にはカートに入っている商品の番号、$_SESSION['quantity'][]にはカートに入っている商品の個数が格納されています。

参考にしたサイト

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

Wordpressで自動投稿システムを作ってみる & functions.phpからWordpressを動かしてみる

はじめに

「投稿した記事を自動的に複製するシステムがほちい」という要望があった。
内容的にはjsで見た目を切り替えるだけのページで偽造してもよかったんだけれど、それだとなんか物足りない。
ので、functions.phpから投稿を管理するシステムを作ってみました。

要件定義

・投稿タイプtypehogeで記事を新規作成、内容を入力して投稿ボタンを押すと、その記事と同じタイトル、カスタムフィールド値(3種)を持つ複製記事がtypehoge2に自動で投稿される

実際のコード

あ、本筋とは外れるけど、functions.phpを改修する上で以下のコードはすげー役に立ったので書いとく。

functions.php
var_dump( $hoge );
exit;

PHP使いならご存じvar_dump()
普段のWordpress改修では欠かせない存在だけれども、値をどこにも格納しないのでfunctions.phpのような表示に使われないファイルでは実質使えないのが難点。しかし、直後にexit;と打っておくと式がvar_dump()を実行した段階で強制終了するので、変数の中身とかを確認できる。便利だった。

……で、本題のコードはこちら。

functions.php
// 投稿の自動複製システム
function function_copying_posts(){

    // 現在動作中の投稿の情報(つまり、新規作成したコピー元……「typehoge」記事の内容)を取得します。
    global $post;

    if($post->post_type == 'typehoge'){
        $current_postID = $post->ID;

        // ACFフィールドに入力された値を取得します。この関数が実行されるタイミングが投稿がデータベースに登録される前なので、$_POSTを用いています。
        $hoge_name = $_POST['acf']["field_5d106111f2430"];
        $hoge_price =  $_POST['acf']["field_5d1060e886e4d"];
        $hoge_comment = $_POST['acf']["field_5d8561357b6fa"];

        // 自動投稿するときのステータスをここで指定します。
        $draft_my_options = array(
            'post_title'    => get_the_title($current_postID),
            'post_content'  => '',
            'post_status'   => 'publish',
            'post_type'      => 'typehoge2'
        );
        // 新しい記事を自動で投稿しつつ、その記事のidを取得します。この行が実行されるタイミングで自動投稿は完了していることに注意してください。
        $newpost_id = wp_insert_post($draft_my_options);

        if($newpost_id){
            // カスタムフィールドに値を挿入してます。
            update_post_meta($newpost_id, 'hoge_name2', $hoge_name);
            update_post_meta($newpost_id, 'hoge_price2', $hoge_price);
            update_post_meta($newpost_id, 'hoge_comment2', $hoge_comment);
        }
    }

}
add_action( 'publish_typehoge', 'function_copying_posts', 9);

解説

コピー元投稿のデータ取得→コピー先投稿を公開→コピー先のカスタムフィールドを上書き……の順番で行っている。

苦労したのはカスタムフィールドに入力した内容を取得する部分。

これはACFに限る話だけれど、どうも記事が投稿されるタイミングよりACFデータがデータベースにアップされるタイミングの方が遅いらしく、get_field()やget_post_meta()だとカスタムフィールドに入力した値を取得できないようだ。
get_field()やget_post_meta()がデータベースからデータを呼び出してくるからだろうか?
入力した内容が消えちまったよクソ

そのへんの話はこのサイトに載ってたけども、とりあえず俺の場合はしゃーなしということでinputからデータを取り出す方式( $_POST['acf']["field_5d106111f2430"] = フィールドキー )にした。

余談

ちなみに、自動投稿を行う部分だけを抜き出すと以下の通りになるらしい。

$post_value = array(

  'post_author' => 1,// 投稿者のID。
  'post_title' => 'テストタイトル',// 投稿のタイトル。
  'post_content' => 'テスト本文', // 投稿の本文。
  'post_category' => array(1,5), // カテゴリーID(配列)。
  'tags_input' => array('タグ1′,'タグ2′), // タグの名前(配列)。
  'post_status' => 'publish' // 公開ステータス。

);
wp_insert_post($post_value);

wp_insert_term()など、自動で管理画面を制御してくれるコードはほかにもいくつかある。

……これ、functionとかadd_actionについて触れた方がよかったのかなあ。

参考資料

http://blog.ale-cole.com/php/wordpress/69/
https://www.advancedcustomfields.com/resources/acf-save_post/
https://teratail.com/questions/107958
https://torounit.com/blog/2013/05/22/1544/

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

Wordpressで自動投稿システムを作ってみる

はじめに

「投稿した記事を自動的に複製するシステムがほちい」という要望があった。
内容的にはjsで見た目を切り替えるだけのページで偽造してもよかったんだけれど、それだとなんか物足りない。
ので、functions.phpから投稿を管理するシステムを作ってみました。

要件定義

・カスタム投稿タイプtypehogeの記事を新規作成、内容(カスタムフィールド含む)を入力して投稿ボタンを押すと、その記事と同じタイトル、およびカスタムフィールド値(3種)を持つ複製記事が、別のカスタム投稿タイプtypehoge2の記事として投稿される

実際のコード

functions.php
// 投稿の自動複製システム
function function_copying_posts(){

    // 現在動作中の投稿の情報(つまり、新規作成したコピー元……「typehoge」記事の内容)を取得します。
    global $post;

    if($post->post_type == 'typehoge'){
        $current_postID = $post->ID;

        // ACFフィールドに入力された値を取得します。この関数が実行されるタイミングが投稿がデータベースに登録される前なので、$_POSTを用いています。
        $hoge_name = $_POST['acf']["field_5d106111f2430"];
        $hoge_price =  $_POST['acf']["field_5d1060e886e4d"];
        $hoge_comment = $_POST['acf']["field_5d8561357b6fa"];

        // 自動投稿するときのステータスをここで指定します。
        $draft_my_options = array(
            'post_title'    => get_the_title($current_postID),
            'post_content'  => '',
            'post_status'   => 'publish',
            'post_type'      => 'typehoge2'
        );
        // 新しい記事を投稿しつつ、その記事のidを取得します。この行が実行されるタイミングで投稿そのものは完了していることに注意してください。
        $newpost_id = wp_insert_post($draft_my_options);

        if($newpost_id){
            // カスタムフィールドに値を挿入してます。
            update_post_meta($newpost_id, 'hoge_name2', $hoge_name);
            update_post_meta($newpost_id, 'hoge_price2', $hoge_price);
            update_post_meta($newpost_id, 'hoge_comment2', $hoge_comment);
        }
    }

}
add_action( 'publish_typehoge', 'function_copying_posts', 9);

解説

コピー元投稿のデータ取得→コピー先投稿を公開→コピー先のカスタムフィールドを上書き……の順番で行っている。

苦労したのはカスタムフィールドに入力した内容を取得する部分。

これはACFに限る話だけれど、どうも記事が投稿されるタイミングよりACFデータがデータベースにアップされるタイミングの方が遅いらしく、get_field()やget_post_meta()だとカスタムフィールドに入力した値を取得できないようだ。
get_field()やget_post_meta()がデータベースからデータを呼び出してくるからだろうか?
入力した内容が消えちまったよクソ

そのへんの話はこのサイトに載ってたけども、とりあえず俺の場合はしゃーなしということでinputからデータを取り出す方式にした。

functions.php
$_POST['acf']["field_5d106111f2430"]

なお、このinputから取り出すコマンド、「field_5d106111f2430」部分を取得したい入力欄にあるフィールドキーに書き換えれば問題なく使えます。

余談

functions.phpを改修する上で以下のコードはすげー役に立ったので書いとく。

functions.php
var_dump( $hoge );
exit;

PHP使いならご存じvar_dump()
普段のWordpress改修では欠かせない存在だけれども、functions.phpのような、表示に使われないphpファイルでは実質使えないのが難点だった。
が、直後にexit;と打っておくと式がvar_dump()を実行した段階で強制終了するので、変数の中身とかを確認できる。
広まれ。

あと、自動投稿を行う部分だけを抜き出すと以下の通りになるらしい。

functions.php
$post_value = array(

  'post_author' => 1,// 投稿者のID。
  'post_title' => 'テストタイトル',// 投稿のタイトル。
  'post_content' => 'テスト本文', // 投稿の本文。
  'post_category' => array(1,5), // カテゴリーID(配列)。
  'tags_input' => array('タグ1′,'タグ2), // タグの名前(配列)。
  'post_status' => 'publish' // 公開ステータス。
);
wp_insert_post($post_value);

wp_insert_term()など、自動で管理画面を制御してくれるコードはほかにもいくつかあるみたい。

参考資料

http://blog.ale-cole.com/php/wordpress/69/
https://www.advancedcustomfields.com/resources/acf-save_post/
https://teratail.com/questions/107958
https://torounit.com/blog/2013/05/22/1544/

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