20190716のPHPに関する記事は16件です。

p+q=r2乗のN以下の素数を求める

問題文

p+q=r2 を満たす N 以下の素数 (p,q,r) の組の個数を求めてください。

ソース

<?php
//入力値
$nyu = 10;

//素数を取得
for($i=2; $i<$nyu; ++$i){
    $flag = 0;
    for($j=2; $j<$i; ++$j){
        if( $i%$j == 0){
            $flag =1;
            break;
        }
    }
    if($flag == 0){
        $retsu[] = $i;
    }
}
//2乗の値を取得
for($i=0; $i<count($retsu); $i++){
    $total[] = $retsu[$i] * $retsu[$i];
}
//計算パターンを2次元配列に格納
foreach ($retsu as $val1) {
    foreach ($retsu as $val2) {
         $result[] = array_merge((array)$val1, (array)$val2);
    }
}
//配列に格納した組み合わせを足し算して、合計と一致するものにカウント+1
for($i=0; $i<count($retsu); $i++){
    for($p=0; $p<count($result); $p++){
        $tasu_kekka = ($result[$p][0] + $result[$p][1]);
        if($tasu_kekka == $total[$i]){
            $kekka[] = 1;
        }
    }
}

echo count($kekka);
?>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MacでLaravel5.8導入 その2 Composer, Laravelのインストール プロジェクト作成

前提

下記のページ(公式ではない?)が非常によくできてるので読めばだいたいわかる
https://readouble.com/

環境:Mac
VirtualBox, Vagrant導入済み
前回の記事で仮想環境構築までは完了済み

Composerの導入

Homebrewを利用
すぐにバージョン古くなってるのでまずはアップデート確認

# ステータスチェック
$ brew doctor
# 問題があれば極力解決しておく

# アップデート
$ brew update

# アップグレード
$ brew upgrade

# エラーが出てなさそうなら、composerのインストール
$ brew install composer

# composerで、Laravelインストーラをダウンロード
$ composer global require laravel/installer

laravelコマンドのパスを通す
.bash_profileに下記を追加
export PATH=$PATH:~/.composer/vendor/bin

プロジェクトを作成したい場所に移動してnewコマンド実行

$ cd ~/myProject
$ laravel new laravelTest

おしまい

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

MacでLaravel5.8導入 導入の下準備_仮想環境構築

前提

下記のページ(公式ではない?)が非常によくできてるので読めばだいたいわかる
https://readouble.com/

環境:Mac
VirtualBox, Vagrant導入済み

導入前の下準備

仮想環境の設定

Homestead というVagrant仮想環境を使うと非常に都合が良いらしい

# Vagrantに、HomesteadのBoxイメージをインストール
$ vagrant box add laravel/homestead

# homeディレクトリにhomesteadのリポジトリをクローン(自分のLaravelの全プロジェクトをホストしておくHomestead Boxを用意するためらしい)
$ git clone https://github.com/laravel/homestead.git ~/Homestead

# 最新のmasterではなく安定版のreleaseブランチに変更
$ cd ~/Homestead
$ git checkout release

# 設定ファイルを作成(Homestead.yaml)
$ bash init.sh

Homestead.yamlの設定

下記以外は特殊な設定がなければ初期設定のままでOK

# 仮想環境に同期したいローカル環境のディレクトリを記載する
# map: ローカル開発環境側  to: 仮想環境側
folders:
    - map: ~/myProject/laravelTest
      to: /home/vagrant/laravelTest

ホスト名の解決

hostsファイルに下記を追加する。192.168.10.10は、IPアドレスの初期値
192.168.10.10 homestead.test

Vagrantの起動

Homesteadの設定が一通り終わったので、Vagrantを起動する。

# Homesteadディレクトリで
$ vagrant up

ブラウザで、homestead.testにアクセスして表示されればOK

仮想環境へのSSH接続

# Homesteadディレクトリで
$ vagrant ssh

アクセスが成功し、ホームディレクトリに同期させたかったディレクトリ, ファイルがあればOK
Homesteadディレクトリ以外からもssh接続できるようにするためには下記を.bash_profileに追加する。

function homestead() {
    ( cd ~/Homestead && vagrant $* )
}

これで他のディレクトリからも
$ homestead ssh
でssh接続できるようになる。(他のvagrantコマンドも)

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

MacでLaravel5.8導入 + 仮想環境構築

前提

下記のページ(公式ではない?)が非常によくできてるので読めばだいたいわかる
https://readouble.com/

環境:Mac
Homebrew, VirtualBox, Vagrant導入済み

まずはComposerの導入

Homebrewを利用
すぐにバージョン古くなってるのでまずはアップデート確認

# ステータスチェック
$ brew doctor
# 問題があれば極力解決しておく

# アップデート
$ brew update

# アップグレード
$ brew upgrade

# エラーが出てなさそうなら、composerのインストール
$ brew install composer

# composerで、Laravelインストーラをダウンロード
$ composer global require laravel/installer

パスを通してプロジェクト作成

laravelコマンドのパスを通す
.bash_profileに下記を追加
export PATH=$PATH:~/.composer/vendor/bin

プロジェクトを作成したい場所に移動してnewコマンド実行

$ cd ~/myProject
$ laravel new laravelTest

これでいったんプロジェクトの作成は完了。

仮想環境の設定

Homestead というVagrant仮想環境を使うと非常に都合が良いらしい

# Vagrantに、HomesteadのBoxイメージをインストール
$ vagrant box add laravel/homestead

# homeディレクトリにhomesteadのリポジトリをクローン(自分のLaravelの全プロジェクトをホストしておくHomestead Boxを用意するためらしい)
$ git clone https://github.com/laravel/homestead.git ~/Homestead

# 最新のmasterではなく安定版のreleaseブランチに変更
$ cd ~/Homestead
$ git checkout release

# 設定ファイルを作成(Homestead.yaml)
$ bash init.sh

Homestead.yamlの設定

下記以外は特殊な設定がなければ初期設定のままでOK

Homestead.yaml
# 仮想環境に同期したいローカル環境のディレクトリを記載する
# map: ローカル開発環境側  to: 仮想環境側
folders:
    - map: ~/myProject/laravelTest
      to: /home/vagrant/laravelTest

ホスト名の解決

hostsファイルに下記を追加する。192.168.10.10は、IPアドレスの初期値
192.168.10.10 homestead.test

Vagrantの起動

Homesteadの設定が一通り終わったので、Vagrantを起動する。

# Homesteadディレクトリで
$ vagrant up

ブラウザで、homestead.testにアクセスして表示されればOK

仮想環境へのSSH接続

# Homesteadディレクトリで
$ vagrant ssh

アクセスが成功し、ホームディレクトリに同期させたかったディレクトリ, ファイルがあればOK
Homesteadディレクトリ以外からもssh接続できるようにするためには下記を.bash_profileに追加する。

function homestead() {
    ( cd ~/Homestead && vagrant $* )
}

これで他のディレクトリからも
$ homestead ssh
でssh接続できるようになる。(他のvagrantコマンドも)

おしまい

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

PHPで4桁以上の金額などの数字をカンマ(,)区切りにする備忘録

sample.php
$sujiA = 493948234153;
$sujiB = number_format($sujiA);
echo $sujiA; // 493948234153
echo $sujiB; // 493,948,234,153
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelコレクションのpluck()メソッドを活用しよう

環境

Laravel Framework 5.8
PHP 7.2

やりたいこと

DBからこのようなデータを取得して、idがキー、カラムデータがバリューとなる、配列を作りたくなることがよくある。

    $collection = collect([
        ['id' => 1, 'name' => 'ジャック鈴木', 'company' => 'Five Needs'],
        ['id' => 2, 'name' => 'Umichiko' , 'company' => 'Five Needs']
    ]);

私はこれまで、このようなときarray_column()を利用して配列を生成していた。

  $user_array = array_column($collection->all(),null,"id");

スマートなやり方

Laravelコレクションの機能であるpluck()メソッドを利用することで同様のことがより簡潔に実現できる。

    $collection = collect([
        ['id' => 1, 'name' => 'ジャック鈴木', 'company' => 'Five Needs'],
        ['id' => 2, 'name' => 'Umichiko' , 'company' => 'Five Needs']
    ]);

    /*
     * nameの値だけを取得できる。
     */
    var_dump($collection->pluck("name"));

    //class Illuminate\Support\Collection#331 (1) {
    //  protected $items =>
    //  array(2) {
    //    [0] =>
    //    string(18) "ジャック鈴木"
    //    [1] =>
    //    string(8) "Umichiko"
    //  }
    //}


    /*
     * キーがidでバリューがnameのコレクションを生成
     */
    var_dump($collection->pluck("name", "id"));

    //class Illuminate\Support\Collection#331 (1) {
    //  protected $items =>
    //  array(2) {
    //    [1] =>
    //    string(18) "ジャック鈴木"
    //    [2] =>
    //    string(8) "Umichiko"
    //  }
    //}



    /*
     * キーがidでバリューに全データが入ったコレクションを生成
     */
    var_dump($collection->pluck(null, "id"));

    //class Illuminate\Support\Collection#331 (1) {
    //  protected $items =>
    //  array(2) {
    //    [1] =>
    //    array(3) {
    //      'id' =>
    //      int(1)
    //      'name' =>
    //      string(18) "ジャック鈴木"
    //      'company' =>
    //      string(10) "Five Needs"
    //    }
    //    [2] =>
    //    array(3) {
    //      'id' =>
    //      int(2)
    //      'name' =>
    //      string(8) "Umichiko"
    //      'company' =>
    //      string(10) "Five Needs"
    //    }
    //  }
    //}

    /*
     * array_columnでも同様のことができる
     */
    var_dump(array_column($collection->all(),null,"id"));
    //array(2) {
    //  [1] =>
    //  array(3) {
    //    'id' =>
    //    int(1)
    //    'name' =>
    //    string(18) "ジャック鈴木"
    //    'company' =>
    //    string(10) "Five Needs"
    //  }
    //  [2] =>
    //  array(3) {
    //    'id' =>
    //    int(2)
    //    'name' =>
    //    string(8) "Umichiko"
    //    'company' =>
    //    string(10) "Five Needs"
    //  }
    //}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CodeceptionのE2EテストでseeInSourceはなるべく使わない方が良い件

背景

Codeceptionで要素を見るためにseeInSourceを使っていたら、ローカルでは通ってもサーバー上では全て落ちていた。

原因

ローカル上のE2Eテストとサーバー上でのE2Eテストで出力されるHTMLが異なる場合があった。
具体的にはサーバー上ではタグに勝手に閉じタグ< />が付くなど。

$I->seeInSource('<meta property="og:title" content="hogehoge">');

とテストコードを書いても

<meta property="og:title" content="hogehoge" />

サーバー上では的な具合でHTMLが出力されてしまう。

対処法

seeInSourceをなるべく使わないこと。
上記の例ではseeElementInDOMを使う。

$I->seeElementInDOM('meta[property="og:title"][content="hogehoge"]');

参考

How to test with Codeception if the page has meta-tag?

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

MacのPHP(Homebrew)でxdebug環境を用意する

Macローカルでデバッグがしたい

Dockerで立てる程ではないものの確認を行いたい場合にいいと思ったので。
PHPのバージョンが同じであれば、Dockerコンテナでも同じ設定で行けそうです。
Windowsはこちら

前提条件

console
% 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

インストール

peclからインストールします。

console
% pecl install xdebug
# --- 中略 ---

# エラーが出る場合
% pecl search xdebug                                                                                                          [master]
Retrieving data...0%
Matched packages, channel pecl.php.net:
=======================================
Package Stable/(Latest)    Local
xdebug  2.8.0alpha1 (beta) 2.8.0alpha1 Provides functions for function traces and profiling

% pecl install -f xdebug-2.8.0alpha1

# 確認
% 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 Xdebug v2.8.0alpha1, Copyright (c) 2002-2019, by Derick Rethans
    with Zend OPcache v7.3.6, Copyright (c) 1999-2018, by Zend Technologies

おまけ: php.iniの場所

console
% php -i | grep php.ini
Configuration File (php.ini) Path => /usr/local/etc/php/7.3
Loaded Configuration File => /usr/local/etc/php/7.3/php.ini

あとは、PhpStormなどで設定するだけ。

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

【web開発� PHP】同ページにHTTPを行いたい!

はじめに

webサービスを開発する際に便利だと思ったので書き起こしています。ButtonやAnchorを用いて同ページに変数を送信(HTTP)したいときに使います。例えば、ページ上のカテゴリボタンを押すとそのページ上でそのカテゴリのみのコンテンツが絞られたものが表示されたり。
以下のコード例では同ページ内に変数を渡す部分を記述しています。

解決法

こちらではPOST送信で書いておりますが、GETでも可。
PHPファイル先頭に以下を記述。もしPOST送信があればdataを受け取りPOSTデータを削除するだけのシンプルなコードです。

if (isset($_POST["btnid"])) {
  $data = $_POST["btnid"];
  unset($_POST);
}

さて、以下のコードが鍵となります。こちらはform要素ですが、画面上には表示されないようになっております。valueには後に送信したい変数を格納するのでデフォルトでは空白。

<form name="form1">
  <INPUT type="hidden" id="btnid" name="btnid" value=""/>
</form>

以下のコードではid="id"である要素をクリックするとvalueに送信したい変数を格納して送信するというものであり、これが実行されると、もう一度index.phpの先頭行から処理ををするため\$data変数に$_POST["btnid"]が送信されるというシンプルなものです。

$("#id").on("click", function(e){
  $("#btnid").val(data); //送信したいデータをvalue値として登録

  let form1 = document.forms["form1"];
  form1.method = "POST"; //HTTP方式の決定
  form1.action = "index.php"; //遷移先を同ファイルに設定
  form1.submit(); //送信
  return false;
});

未解決事項

色々調べてみたものの、一番よく見かけたのはAjaxでの送信でしたが今回はうまく実装できませんでした。AjaxはGoogle検索する時に、文字を少しタイプすると下に検索予想が出てくる機能に使われているようで、常にHTTP方式で送信している感じらしいです。おそらく、今回実装できなかったのは要素がクリックした時にのみ発火されるというものに相性が良くなかったのかなと思いますが、今後の実装でもう一度勉強しようと思います。

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

【web開発】PHPで同ページにHTTPを行いたい!

はじめに

webサービスを開発する際に便利だと思ったので書き起こしています。ButtonやAnkerを用いて同ページに変数を送信(HTTP)したいときに使います。例えば、ページ上のカテゴリボタンを押すとそのページ上でそのカテゴリのみのコンテンツが絞られたものが表示されたり。
以下のコード例では同ページ内に変数を渡す部分を記述しています。

解決法

こちらではPOST送信で書いておりますが、GETでも可。
PHPファイル先頭に以下を記述。もしPOST送信があればdataを受け取りPOSTデータを削除するだけのシンプルなコードです。

if (isset($_POST["btnid"])) {
  $data = $_POST["btnid"];
  unset($_POST);
}

さて、以下のコードが鍵となります。こちらはform要素ですが、画面上には表示されないようになっております。valueには後に送信したい変数を格納するのでデフォルトでは空白。

<form name="form1">
  <INPUT type="hidden" id="btnid" name="btnid" value=""/>
</form>

以下のコードではid="id"である要素をクリックするとvalueに送信したい変数を格納して送信するというものであり、これが実行されると、もう一度index.phpの先頭行から処理ををするため\$data変数に$_POST["btnid"]が送信されるというシンプルなものです。

$("#id").on("click", function(e){
  $("#btnid").val(data); //送信したいデータをvalue値として登録

  let form1 = document.forms["form1"];
  form1.method = "POST"; //HTTP方式の決定
  form1.action = "index.php"; //遷移先を同ファイルに設定
  form1.submit(); //送信
  return false;
});

未解決事項

色々調べてみたものの、一番よく見かけたのはAjaxでの送信でしたが今回はうまく実装できませんでした。AjaxはGoogle検索する時に、文字を少しタイプすると下に検索予想が出てくる機能に使われているようで、常にHTTP方式で送信している感じらしいです。おそらく、今回実装できなかったのは要素がクリックした時にのみ発火されるというものに相性が良くなかったのかなと思いますが、今後の実装でもう一度勉強しようと思います。

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

偶数だけを繰り返し表示する(PHP)

簡単だけど文法等をすっきり落とし込むためにアウトプット。

やること
1から100までの数字から偶数だけ表示させる

どうやったか

<?php
  $i = 1;  //変数を定義

  while($i <= 100) {
    if($i % 2 == 0) {
      echo $i;
      echo '<br>';
    }
    $i ++;
  }
?>

1から100までを繰り返すWhile文の中で2で割り切れる数字(偶数)だけを表示させています。
これ自体は難しくはないけどこういった発想の組み合わせが大事だと思いました。

(追加)

 for($i = 1;$i <= 100; $i++) {
   if($i % 2 == 1){
     continue;
   }
   echo $i;
   echo '<br>';
 }

もしくはfor文で奇数だけスキップなんてやり方もありますね。

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

PHP の mysqli, mysqlnd, pdo_mysql, PDO, libmysqlclient まとめ

PHP で MySQL を利用する時、通常は PHP 拡張モジュール(extension)を用いて接続します。

その時、 mysqli, mysql, mysqlnd, pdo_mysql, PDO, libmysqlclient といったわかりづらい名前の諸々があるので、ここでまとめておきます。

拡張モジュール

php.ini
extension=mbstring.so

こんな感じで設定を書くことで、ネイティブ C で記述された機能を PHP 上で利用出来るようになります。

PHP の実装よりも高速に動作するため、 MySQL との通信処理など処理速度がボトルネックになるようなものは拡張モジュールとして実装することで、処理速度の向上をしています。

拡張モジュール用ライブラリ

まず、 MySQL 拡張モジュールを実装する際にベースとされるライブラリがあります。

現状は mysqlndlibmysqlclient のどちらかです。

PHP: どのライブラリを選ぶか - Manual

これらは、 PHP のコンパイル時に --with-pdo-mysql=mysqlnd などと指定して選ぶことが可能です。

mysqlnd

MySQL Native Driver が現在推奨されているネイティブライブラリで、デフォルトでこれが使われます。

libmysqlclient よりも様々な点で優れているため、こちらを選ぶことがほとんどのケースで最適です。

mysqlnd それ自体も PHP 拡張モジュールとして実装されているため、パフォーマンスも高いです。

libmysqlclient

mysqlnd の前に MySQL チーム(現 Oracle)が作成した、 PHP 依存のない純粋な C 言語のライブラリです。

利用時に MySQL をインストールする必要があったり、 MySQL ライセンスのため PHP に同梱出来なかったりと欠点がいくつかあります。

サポート自体は継続されていますが、一般に利用することはほぼないでしょう。

まとめ1

  • mysqlndlibmysqlclient は MySQL に接続するためのベースライブラリで選択可能
  • 基本は mysqlnd を選択する

mysql

単純に mysql と言った時は、大体 PHP 2.0 からある古い拡張モジュールのことを指します。

mysql_connect 関数などを提供している extension ですが、 PHP 7 以降は利用出来ません。

なので、この拡張モジュールは新規開発では利用されないでしょう。そもそもトランザクションすらないので、実用性もありません。
超絶古い PHP 3 や 4 で開発されたプロダクトがまだ生きていて、保守しなければならない時に見かけることがあるかもしれない、くらいです。

mysqli

MySQL Improved 拡張モジュールです。公式ではこの拡張モジュールが推奨されています。

$mysqli = new mysqli("example.com", "user", "password", "database");
if ($mysqli->connect_errno) {
    echo "Failed to connect to MySQL: " . $mysqli->connect_error;
}

$res = $mysqli->query("SELECT 'choices to please everybody.' AS _msg FROM DUAL");
$row = $res->fetch_assoc();
echo $row['_msg'];

こんな感じで手軽にクエリを投げることが出来る API を提供しています。

mysql と似た API も提供しているので、移行も比較的楽に可能です。

PDO

PHP の基本機能として、複数のデータベースアプリケーション(MySQL, sqlite, Oracle など...)間で出来るだけインターフェースを統一し、同じ PHP コードで別 DB にも投げれるようにした API 実装が PDO です。

これを使うことで、接続先のDB用のドライバを切り替えるだけで手軽に別の DB アプリケーションへ移行することが出来ます。
(実際に別の DB アプリケーションに移行することがあるのかはおいといて)

Laravel や CakePHP は PDO をラップして実装されているので、 mysqli 拡張モジュールを利用することは出来ません。
逆に、 Doctrine や CodeIgniter は mysqli を使うことも可能です。

PDO を利用するのであれば、 extension=mysqli として mysqli 拡張モジュールを有効にする必要はありません。

pdo_mysql

pdo_mysql 拡張モジュールは、 PDO API で MySQL に接続するためのドライバです。

PDO を使って MySQL に接続したい場合はこの拡張モジュールを有効にする必要があります。

他にも、 pdo_sqlite pdo_pgsql などのドライバ拡張モジュールがあり、それらを有効にすることで PDO を通して接続可能になります。

まとめ2

  • mysql はもう使われない古い拡張モジュール
  • mysqli は推奨されている拡張モジュール
  • pdo_mysql は他の DB に繋ぐことも考えた抽象化層である PDO を一個挟んだ拡張モジュール

フレームワークや OR マッパーによってこの辺りは隠蔽されることがほとんどですが、実際に使われている拡張モジュールが何かを知ることは php.ini の設定や Dockerfile を書く時などで必要になってきます。これでもう間違わないで拡張モジュールを選べるようになったのではないでしょうか。

参考資料

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

PHP中身を途中で確認する方法

vardump();die;

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

php-master-changes 2019-07-15

今日は不要コードの削除、ドキュメントの更新、opcache_get_configuration() で ini_get_all('zend opcache') でとれる結果が全てとれない問題の修正、AArch64 用の文字列エスケープの最適化、循環参照GC で SEGV が起きる問題の修正、字句解析器で無効な文字向けに T_BAD_CHARACTER を吐くようにする修正、date.sunset_zenith と date.sunrise_zenith のデフォルト値を 90.583333 から 90.833333 にする修正、password_hash() が argon2 で弱いオプションを使う問題の修正、mysqlnd のバージョン番号に PHP バージョンを使うようにする修正、ftp のリーク修正の 7.2 系以降へのバックポート、shebang の対応を字句解析器内で行うようにする修正があった!

2019-07-15

petk: Remove unsed zts check for sqlite3

petk: Remove conditional calls of always available macros

petk: Symbol HAVE_PCRE has been removed

petk: Remove usage of PHP_AIX_LDFLAGS

amnuts: Fix bug #78291 Missing opcache directives

sebpop: vectorize string-escape with NEON

nikic: Fixed bug #78010

nikic: Remove unused is_constructor arguments

nikic: Emit T_BAD_CHARACTER for unexpected characters

cmb69: Fix #65547: Default value for sunrise/sunset zenith still wrong

  • https://github.com/php/php-src/commit/7556600dfc80e9a11db538ce58cb249d6cdda7b3
  • ext/date で、date.sunset_zenith と date.sunrise_zenith が一般的な値でなかった問題の修正
  • 90°50' を使って 90.833333 になると思いきや 90°35' で 90.583333 になっており、その根拠がよく分からない感じだった
  • sunrise とか sunset でとる値が PHP 8 で(デフォルトでは)変わるので、使ってる人は急にテストこけてびびらされたりするかもしれない?

remicollet: Fix #78269 password_hash uses weak options for argon2

remicollet: typo [ci skip]

cmb69: Sync mysqlnd version with PHP version

nikic: Fix bug #77124

nikic: Move shebang handling into the lexer

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

PHPでGuzzleを使ったHTTPリクエスト

はじめに

PHPからguzzleを使用して外部API(GithubやQiitaなど)をシンプルに実行するためのメモです。
エラー処理だけLaravel独自のメソッドがありますが、ほとんどフレームワークを選ばず使用できます。

guzzleとは

シンプルなインターフェースで同期、非同期リクエストを行えるPHPのHTTPクライアントになります。

詳しくはこちら↓
https://github.com/guzzle/guzzle

実装

まずはベース部分を実装します。

    /**
     * @param string $base_url
     * @param string $path
     * @param array $headers
     * @param array $form_params
     * @param string $method
     * @return array
     */
    private function requestClient(
        string $base_url,
        string $path,
        array $headers,
        array $form_params = [],
        string $method = 'GET'
    ): array {
        try {
            $client = new \GuzzleHttp\Client([
                'base_uri' => $base_url,
            ]);

            $response = $client->request($method, $path, [
                'headers' => $headers,
                'form_params' => $form_params,
            ]);
            return json_decode($response->getBody()->getContents(), true);
        } catch (\GuzzleHttp\Exception\GuzzleException $e) {
            report($e); // ログ出力
            return [];
        }
    }
Qiitaからの取得
    /**
     * @return array
     */
    public function getQiitaList(): array
    {
        $base_url = 'https://qiita.com';
        $path = '/api/v2/authenticated_user/items?page=1&per_page=20';
        $headers = ['Authorization' => 'Bearer xxxxxxxxxxxxxxxxx'];
        return $this->requestClient($base_url, $path, $headers);
    }
Githubからの取得
    /**
     * @return array
     */
    public function getGithubList(): array
    {
        $base_url = 'https://api.github.com';
        $path = '/repos/terumichi1209/laravel-test/commits?sha=develop';
        $headers = [];
        return $this->requestClient($base_url, $path, $headers);
    }

終わりに

要件によってはこの辺りのオプション使うと良さそうです。
http://docs.guzzlephp.org/en/latest/request-options.html

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

Laravel[業務効率化]自動migrationファイル作成ツールをつくってみた話

作成するにあたっての動機

今まで、Laravelを使ったプロジェクトにかかわらせていただくことがあり、DB設計を終えた後に、sqlファイルやddlファイルを自動で作ってくれるものはあるのに、それを元にマイグレーションファイルを自動で作ってくれるものがないので、大変だぁと思い、取り組んでみました。

こうしたほうがいい(特にカプセル化・命名などなど)などの意見をぜひほしいです。新米のため、すごく助かります。もしよろしければ、お願いいたします。

最終目的

すでに作成されているテーブルからマイグレーションファイルを自動で作れるようにします。

準備

プロジェクト作成

コマンド
composer create-project --prefer-dist laravel/laravel autoCreateMigrationFileSystem

テーブル作成

今回は、laravelのmigrationファイルを作成・実行し、テーブルを作り、そこから同じファイルが作成されるかをテストします。

実際は複数テーブルがあるため、2つのテーブルを用意する。

・applesテーブル

・lemonsテーブル

コマンド
/var/www# php artisan make:migration create_apples_table
Created Migration: 2019_07_15_133234_create_apples_table
/var/www# php artisan make:migration create_lemons_table
Created Migration: 2019_07_15_133511_create_lemons_table

僕が今回参加するプロジェクトで使うカラムタイプが補えればいいので、それだけ洗い出す(新たに必要なカラムタイプは後から加えていく)

今回使うカラムタイプ

  • bigint(20)のauto_increment
  • bigint(20)
  • bigint(20) nullable
  • bigint(20) default(0)
  • varchar(255)
  • timestamp (created_atとupdated_atで使用する)
  • int(11)
  • tinyint(4)
  • text
  • date
  • datetime

これらを二つのマイグレーションファイルに記述します。

CreateApplesTable.php
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateApplesTable extends Migration
{
    public function up()
    {
        Schema::create('apples', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->bigInteger('a');
            $table->bigInteger('b')->nullable();
            $table->bigInteger('c')->default(0);
            $table->string('d', 255);
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('apples');
    }
}
CreateLemonsTable.php
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateLemonsTable extends Migration
{
    public function up()
    {
        Schema::create('lemons', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->integer('e');
            $table->tinyInteger('f');
            $table->text('g');
            $table->date('h');
            $table->dateTime('i');
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('lemons');
    }
}

コマンド
/var/www# php artisan migrate
Migration table created successfully.
Migrating: 2019_07_15_133234_create_apples_table
Migrated:  2019_07_15_133234_create_apples_table
Migrating: 2019_07_15_133511_create_lemons_table
Migrated:  2019_07_15_133511_create_lemons_table

これで準備が完了しました。

実装

今回作るファイル(4ファイル)
- app/Repositories/Repository.php
- views/create_table_stub.blade.php
- config/column_type.php
- app/Console/Commands/MakeMigrationFile.php

app/Repositories/Repository.php(カラム情報を取得するよう)

Repository.php
<?php
namespace App\Repositories;

use Illuminate\Support\Facades\DB;


class Repository
{
    //それぞれのテーブルごとのカラム情報を取得する
    public static function getTableColumnsList()
    {
        $tableColumnsList = [];

        $tableNameList = self::getTableNameList();

        foreach ($tableNameList as $tableName){
            $tableColumnsList[$tableName] = DB::select('show columns from '. $tableName);
        }

        return $tableColumnsList;
    }

    //テーブルの名前を一覧取得する(migrationsテーブルは必要ないので、取得したものからはずす)
    private static function getTableNameList()
    {
        return collect(DB::select('show tables'))
            ->keyBy('Tables_in_'. env('DB_DATABASE'))
            ->forget('migrations')
            ->keys();
    }
}

getTableNameListの実行結果

Screenshot_1.png

getTableColumnsListの実行結果(applesテーブルの中身の写真だけ(長いので・・・・)

Screenshot_2.png
Screenshot_3.png

ファイルを作る用のフォーマットを作成する(views/create_table_stub.blade.php)

create_table_stub.blade.phpをview配下に作成する。

create_table_stub.blade.php
@php $phpTag = '<?php' @endphp
{!! $phpTag !!}
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class {{$className}} extends Migration
{
    public function up()
    {
        Schema::create('{{$tableName}}', function (Blueprint $table) {
@foreach($defineColumnList as $defineColumn)
            $table->{!! $defineColumn !!};
@endforeach
        });
    }

    public function down()
    {
        Schema::dropIfExists('{{$tableName}}');
    }
}

@foreachを一番左にしているのは、ファイルを作成したときにインデントを整えるためです。
{{}}ではなく、{!! !!}を使っているところは、エスケープされると都合がよくないため、こうしています。

どのカラムタイプならどのマイグレーション用のメソッドを使うか決めておく(config/column_type.php)

今回使用する必要があるのだけ、定義しました。(後々必要なものは足して、完成度を上げていく)

column_type.php
<?php
return [
    'auto_increment' => [
        'bigint(20) unsigned' => 'bigIncrements'
    ],

    'bigint(20)' => 'bigInteger',
    'int(11)'    => 'integer',
    'tinyint(4)' => 'tinyInteger',
    'date'       => 'date',
    'datetime'   => 'dateTime',
    'text'       => 'text',

    //サイズ考慮する必要のあるタイプ
    'length' => [
        'varchar' => 'string'
    ]
];

auto_incrementは特殊パターンとして、またサイズを考量すべきものは、length配列の中に入れています。
今後、min maxや from toを使用するメソッドを使いたい場合はその時に強化します。
created_atとupdated_atのtimestampsメソッドは後々処理で追加します。
ちなみに、公式に使用できるカラムタイプが書いてあるので、そこを参考にしました

コマンド
/var/www# php artisan config:clear

コマンドを打ち、設定を反映させました。

コマンドで自動作成が動くようにする。(app/Console/Commands/MakeMigrationFile.php)

コマンドを打ち、ファイルを作成します。

コマンド
/var/www# php artisan make:command MakeMigrationFile
Console command created successfully.
MakeMigrationFile.php
<?php

namespace App\Console\Commands;

use App\Repositories\Repository;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;

class MakeMigrationFile extends Command
{
    protected $signature   = 'make:migration-file';
    protected $description = 'マイグレーション用ファイルを自動作成';

    public function __construct()
    {
        parent::__construct();
    }

    public function handle()
    {
        $configColumnType = config('column_type');

        $tableColumnsList = Repository::getTableColumnsList();
        foreach ($tableColumnsList as $tableName => $columnList) {

            $tempDefineColumnList = [];
            foreach ($columnList as $index => $column) {

                if ($column->Extra === 'auto_increment') {
                    $tempDefineColumnList[$index] = "{$configColumnType['auto_increment'][$column->Type]}('{$column->Field}')";
                    continue;
                }

                if (isset($configColumnType[$column->Type])) {
                    $tempDefineColumnList[$index] = "{$configColumnType[$column->Type]}('{$column->Field}')";

                    if ($column->Null === 'YES')      $tempDefineColumnList[$index] .= '->nullable()';
                    if (strlen($column->Default) > 0) $tempDefineColumnList[$index] .= "->default({$column->Default})";
                    continue;
                }

                $tempColumnType = preg_replace('/(\(|\)|[0-9])/', '', $column->Type);
                if (isset($configColumnType['length'][$tempColumnType])) {

                    $tempLength = preg_replace('/[^0-9]/', '', $column->Type);
                    $tempDefineColumnList[$index] = "{$configColumnType['length'][$tempColumnType]}('{$column->Field}', {$tempLength})";
                    continue;
                }

                //(特殊パターン)created_atとupdated_atのtimestampsメソッド
                if ($column->Field === 'created_at' && isset($columnList[$index + 1]) && $columnList[$index + 1]->Field === 'updated_at') {
                    $tempDefineColumnList[$index] = 'timestamps()';
                    continue;
                }
            }

            $tempClassName  = 'Create'. Str::studly($tableName). 'Table';

            $tempContent = view('create_table_stub', [
                'className'        => $tempClassName,
                'tableName'        => $tableName,
                'defineColumnList' => $tempDefineColumnList
            ])->render();

            $fileNamePrefix = Carbon::now()->format('Y_m_d_His');
            $tempFilePath   = database_path("migrations/{$fileNamePrefix}_create_{$tableName}_table.php");

            File::put($tempFilePath, $tempContent);
        }
    }
}

こんな時間かぁー、自分の実力だとこのあとの改造(カプセル化やもっと短く書けるかなどを考える)と寝る時間が無くなってしまうので(あした会社のため)、とりあえず、要件は満たしたのでこれで、実行する。(handle内のカプセル化や足りない処理はまた今度修正)

コマンド
php artisan make:migration-file

中身が同じマイグレーションファイルができました。いったん完了。

問題点

  • MakeMigrationFile.phpのhandleメソッドの中身をカプセル化する
  • lengthのほうのnullableとdefaultが考慮されていないため、その処理を加える。(その場合stringはデフォルト値をクォテーションで囲む)
  • 命名ももっといいのがある

まとめ

意外と要件を満たすだけならさくっとできました。よかった明日会社で使ってみよ。
こうしたほうがいい(特にカプセル化・命名などなど)などの意見をぜひほしいです。新米のため、すごく助かります。もしよろしければ、お願いいたします。

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