20200226のPHPに関する記事は18件です。

response()->json() と return [a, b, c]のちがい

Too Long; Don't Read

LaravelでのAPIレスポンスの書き方において、  
以下の2つが同じ意味だと思っていた。

return response()->json(
    $response['error_message'],
    $response['status_code'],
    $response['example_text']
);

return [ 
    $response['error_message'],
    $response['status_code'],
    $response['example_text'] 
];

json()の省略形が[]かな くらいに思っていた。

それぞれの結果は以下。

return response()->json(
    $response['error_message'],
    $response['status_code'],
    $response['example_text']
);

// Type error: Argument 3 passed to Illuminate\Routing\ResponseFactory::json() must be of the type array, string given, called in ~~~~

return [ 
    $response['error_message'],
    $response['status_code'],
    $response['example_text'] 
];

// { 'error_message', 500, 'example text' }

前者はエラーが起こっているのに対し、
後者は渡した内容をjson型にしている。

題目のresponse()->json() と return [a, b, c]のちがい
とは、この点になる。

後述するが、json()の引数はそれぞれ格納するものが決まっていて、第二引数以降にオプションを指定することができる。

そのため、
ただjson型のデータを渡せば良い時と、
オプションを指定して受け取り手へ明示的に値を渡したい時とで、使い分けると良い。

今回の場合は
ajaxのdone(), fail() への振り分けを行いたかったことから、
第2引数でHttpステータスを明示できるjson()の書き方を用い、
以下の書き方に変更して無事解決。

return response()->json(
    $response, 
    $response['status']
);

勘違いの要因

return response()->json( ['a', 'b', 'c'] );

配列でjson()に渡すパターンとjson関数の仕様をごっちゃに覚えていたから。

json( )の仕様

json()はjson_encode()を内部で用いている。

json_encode ( mixed $value [, int $options = 0 [, int $depth = 512 ]] ) : string

value
エンコードする値。 リソース 型以外の任意の型を指定できます。
options
JSON_FORCE_OBJECT, .....からなるビットマスク。

以降Arrayで渡す

depth
最大の深さを設定します。正の数でなければいけません。

引数にはそれぞれ受け付ける型と意味が決まっているため、
Arrayで渡すべきところにStringを渡して、型エラーが出ていたのでした。

感想

調べているうちにAjaxのdone, fail の振り分けについても詳しくなれたので良かった。

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

【PHP】変数の初期値の設定

はじめに

データの初期値をまとめておく

各データの初期値

初期値
string ””
integer 0
double 0.0
array []
boolean true
object NULL

やったことあるミス

  • integer型なのに初期値が空文字(“”) → 当時は””が空文字だと理解していなかった
  • なんでもかんでもnull → nullは未定義で変数に値を格納しない状態なので良くない??
  • objectを連想配列と勘違い → arrayとobjectの違いを理解していなかった

さいごに

nullの使い所が完全に理解できてない気がする
次回はarrayとobjectの違いをまとめる

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

インフラ知識低のレイヤから勉強(01)

初めまして、潔(日本語の名)と申します。インフラ部は知識がありますが、バラバラです。具体的から勉強したことがありません。仕事の職場では大変ことがあります。考えているのはITエンジニアなら、インフラのことが知った方はいいともいますので、インフラの知識を調べて、メモを記入します。大先輩のオススメは低のレイヤの勉強から始まることです。下記の順番に記入する予定です。

一段階

1. Apacheをソースコードからコンパイルおよびインストール
2. PHPをSource Codeからコンパイルおよびインストール
3. PHPのMySQL Extenstionをソースコードからコンパイルおよびインストール
4. MySQLをソースコードからコンパイルおよびインストール
5. PHP FrameworkをInstall

二段階

1. Apache、MySQL、PHPのインストール
2. PHP FrameworkをInstall

三段階

1. Dockerのインストール
2. Apache + PHP Containerの構築
3. MySQL Containerの構築
4. PHP FrameworkをInstall

四段階

1. KubernetesでPHP/MySQL Webをデプロイしてみます

じゃあ、上から最後まで進めていきましょう。

最初は環境を準備しなければならない。Vagrantをきめます。

■ Vagrant環境を準備

vagrant up
vagrant ssh

さて、Vagrant環境で操作していきます

■ Apache HTTP Server 2.4.34のソース展開

方法#1:サイトからプルしていきます

cd /usr/local/src
sudo wget http://www-us.apache.org/dist/httpd/httpd-2.4.34.tar.gz
sudo gzip -d httpd-2.4.34.tar.gz
sudo tar xvf httpd-2.4.34.tar

方法#2:Apacheのダウンロードのページにアクセスして、リンクをクリックします

リンク:https://httpd.apache.org/download.cgi

vagrant ssh
cd /var/www/devOps
sudo cp httpd-2.4.34.tar.gz /usr/local/src
cd /usr/local/src
tar zxvf httpd-2.4.34.tar.gz

■ APR と APR-Utilの準備
Apache Portable Runtimeのページにアクセスして、
・apr-1.5.2.tar.gz
・apr-util-1.5.4.tar.gz
をダウンロードします

cd /usr/local/src
sudo wget https://archive.apache.org/dist/apr/apr-1.5.2.tar.gz
sudo gzip -d apr-1.5.2.tar.gz
sudo tar xvf apr-1.5.2.tar
# 展開したディレクトリをApacheのsrclibディレクトリにコピー。
sudo cp -Rp apr-1.5.2 httpd-2.4.34/srclib/apr


sudo wget https://archive.apache.org/dist/apr/apr-util-1.5.4.tar.gz
sudo gzip -d apr-util-1.5.4.tar.gz
sudo tar xvf apr-util-1.5.4.tar
# 展開したディレクトリをApacheのsrclibディレクトリにコピー。
sudo cp -Rp apr-util-1.5.4 httpd-2.4.34/srclib/apr-util

■ configure実行

cd httpd-2.4.34
sudo ./configure

■ make・make installを実行します

sudo make
sudo make install

注意:インストールするときエラー

1。APRのインストールしていない

checking for APR... no
configure: error: APR not found.  Please read the documentation.

解決方法

APRのインストールしていきます
cd /usr/local/src
sudo wget https://archive.apache.org/dist/apr/apr-1.5.2.tar.gz
sudo gzip -d apr-1.5.2.tar.gz
sudo tar xvf apr-1.5.2.tar
# 展開したディレクトリをApacheのsrclibディレクトリにコピー。
sudo cp -Rp apr-1.5.2 httpd-2.4.34/srclib/apr

2。Perl-Compatible Regular Expressions Library(PCRE)をインストールしていない

checking for pcre-config... false
configure: error: pcre-config for libpcre not found. PCRE is required and available from http://pcre.org/

解決方法#1
・pcre.orgサイトからpcreをダウンロードします
・プレフィックスをつけてコンパイルして、インストルします

vagrant ssh
cd /usr/local/src/
cd pcre.8.39
sudo ./configure --prefix=/usr/local/pcre
sudo make
sudo make install

・Apacheがインストールされているところで、pcreをつ使用してApacheをコンパイルします

cd http httpd-2.4.34
sudo ./configure --with-pcre=/usr/local/pcre
sudo make make install

解決方法#2
pcre-develをインストルするだけでした

# Fedora Linux
yum install -y pcre-devel

解決方法#3
RHEL3では、pcre-configを指します。

./configure --prefix=/usr/local/apache2 --with-pcre=/usr/local/pcre

これでApacheのインストールが完了しました。

次にいきましょう!

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

「インフラ知識」低のレイヤの勉強(01)

初めまして、潔(日本語の名)と申します。インフラ部は知識がありますが、バラバラです。具体的から勉強したことがありません。仕事の職場では大変ことがあります。考えているのはITエンジニアなら、インフラのことが知った方はいいともいますので、インフラの知識を調べて、メモを記入します。大先輩のオススメは低のレイヤの勉強から始まることです。下記の順番に記入する予定です。

一段階

1. Apacheをソースコードからコンパイルおよびインストール
2. PHPをSource Codeからコンパイルおよびインストール
3. PHPのMySQL Extenstionをソースコードからコンパイルおよびインストール
4. MySQLをソースコードからコンパイルおよびインストール
5. PHP FrameworkをInstall

二段階

1. Apache、MySQL、PHPのインストール
2. PHP FrameworkをInstall

三段階

1. Dockerのインストール
2. Apache + PHP Containerの構築
3. MySQL Containerの構築
4. PHP FrameworkをInstall

四段階

1. KubernetesでPHP/MySQL Webをデプロイしてみます

じゃあ、上から最後まで進めていきましょう。

最初は環境を準備しなければならない。Vagrantをきめます。

■ Vagrant環境を準備

vagrant up
vagrant ssh

さて、Vagrant環境で操作していきます

■ Apache HTTP Server 2.4.34のソース展開

方法#1:サイトからプルしていきます

cd /usr/local/src
sudo wget http://www-us.apache.org/dist/httpd/httpd-2.4.34.tar.gz
sudo gzip -d httpd-2.4.34.tar.gz
sudo tar xvf httpd-2.4.34.tar

方法#2:Apacheのダウンロードのページにアクセスして、リンクをクリックします

リンク:https://httpd.apache.org/download.cgi

vagrant ssh
cd /var/www/devOps
sudo cp httpd-2.4.34.tar.gz /usr/local/src
cd /usr/local/src
tar zxvf httpd-2.4.34.tar.gz

■ APR と APR-Utilの準備
Apache Portable Runtimeのページにアクセスして、
・apr-1.5.2.tar.gz
・apr-util-1.5.4.tar.gz
をダウンロードします

cd /usr/local/src
sudo wget https://archive.apache.org/dist/apr/apr-1.5.2.tar.gz
sudo gzip -d apr-1.5.2.tar.gz
sudo tar xvf apr-1.5.2.tar
# 展開したディレクトリをApacheのsrclibディレクトリにコピー。
sudo cp -Rp apr-1.5.2 httpd-2.4.34/srclib/apr


sudo wget https://archive.apache.org/dist/apr/apr-util-1.5.4.tar.gz
sudo gzip -d apr-util-1.5.4.tar.gz
sudo tar xvf apr-util-1.5.4.tar
# 展開したディレクトリをApacheのsrclibディレクトリにコピー。
sudo cp -Rp apr-util-1.5.4 httpd-2.4.34/srclib/apr-util

■ configure実行

cd httpd-2.4.34
sudo ./configure

■ make・make installを実行します

sudo make
sudo make install

注意:インストールするときエラー

1。APRのインストールしていない

checking for APR... no
configure: error: APR not found.  Please read the documentation.

解決方法

APRのインストールしていきます
cd /usr/local/src
sudo wget https://archive.apache.org/dist/apr/apr-1.5.2.tar.gz
sudo gzip -d apr-1.5.2.tar.gz
sudo tar xvf apr-1.5.2.tar
# 展開したディレクトリをApacheのsrclibディレクトリにコピー。
sudo cp -Rp apr-1.5.2 httpd-2.4.34/srclib/apr

2。Perl-Compatible Regular Expressions Library(PCRE)をインストールしていない

checking for pcre-config... false
configure: error: pcre-config for libpcre not found. PCRE is required and available from http://pcre.org/

解決方法#1
・pcre.orgサイトからpcreをダウンロードします
・プレフィックスをつけてコンパイルして、インストルします

vagrant ssh
cd /usr/local/src/
cd pcre.8.39
sudo ./configure --prefix=/usr/local/pcre
sudo make
sudo make install

・Apacheがインストールされているところで、pcreをつ使用してApacheをコンパイルします

cd http httpd-2.4.34
sudo ./configure --with-pcre=/usr/local/pcre
sudo make make install

解決方法#2
pcre-develをインストルするだけでした

# Fedora Linux
yum install -y pcre-devel

解決方法#3
RHEL3では、pcre-configを指します。

./configure --prefix=/usr/local/apache2 --with-pcre=/usr/local/pcre

これでApacheのインストールが完了しました。

次にいきましょう!

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

【Laravel】フラッシュデータを使おう

はじめに

Laravelを触り始めた時、簡単なCRUD機能を持ったToDoアプリを作りました。
その時、データベースに保存したり、削除したりできるような機能を実装していました。
しかし、保存ボタンや削除ボタンを押してもアクションの処理が走るだけで味気ないです。保存できても出来てなくてもリダイレクトしたページを表示するだけです。
そんな味気ないアプリケーション嫌だ!!!!「保存に成功しました」ぐらいのステータスメッセージを表示はしてほしい。。。メッセージがないと成功か失敗かわからないですよね。
しかし、意外とステータスメッセージを自力で実装することはめんどくさいです。その理由を2つあげます。。

  • 保存処理が実行した時にメッセージの内容を設定します。保存処理では最後にリダイレクトすることがほとんどだと思うので、メッセージの内容をリダイレクト先のアクションへ渡します。受け取ったアクションからビューへ受け渡すようにコードを書かないといけません。
  • ステータスメッセージの表示は基本的に一回だけです。保存処理後のリダイレクト先のページから他のページにアクセスする時にメッセージを表示されないようにしないといけません。

上記の理由でステータスメッセージを自力で実装するのはとてもめんどくさいです。。
そんな時にセッションのフラッシュデータです!!!
セッション?フラッシュデータ?となると思いますので、ざっくり説明します
セッションを使うことでWebブラウザが閉じるまで一時的にサーバー側にデータを保存することが出来ます
フラッシュデータは次のリクエストまでの間セッションに保存されるデータのことです。
次のリクエスト(他のページへアクセスなど)では削除されます。ですので、フラッシュデータは主にステータスメッセージなど継続しない情報にはもってこいです!!

ではフラッシュデータを使ってステータスメッセージを表示させる方法を解説します。

フラッシュデータの渡し方

フラッシュデータの渡し方は主に3種類あります

flashメソッドで渡す

Flashメソッドを使うとセッションへstatusという名前のデータを保存できます。
statusの中身は処理が完了しましたです

保存アクション内
$request->session()->flash('status', '処理が完了しました');
return redirect('/');

スタティックメソッドを使う

Sessionクラスのflashメソッドを使うことでも値を渡すことができます

保存アクション内
\Session::flash('flash_message', '処理が完了しました');
return redirect('/');

withメソッドを使う

flashメソッドと同じようにフラッシュデータを渡せるwithメソッドもあります

保存アクション内
return redirect('dashboard')->with('status', '処理が完了しました');

ビューでの表示

次にビューでの表示の仕方について説明します
Bootstrapを使えばいい感じに表示してくれます

@if (session('status'))
    <div class="alert alert-success">
        {{ session('status') }}
    </div>
@endif

以上がフラッシュデータを使ったステータスメッセージの表示仕方です。

おまけ

以下おまけです。

フラッシュデータを1つ先のリクエストまで持続させたい場合

reflashメソッドを使うと全フラッシュデータを次のリクエストまで保持できます。

$request->session()->reflash();

特定のフラッシュデータのみ持続させたい場合

keepメソッドを使います。

$request->session()->keep(['user', 'email']);

以上です!!!
ここまで読んでいただきありがとうございました!!
疑問、気になるところがございましたら、質問、コメントよろしくお願いします!!!

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

MODx Evolutionのエレメントをファイル出力する

MODx Evolutionは、CMSとしても、ライトなWebアプリケーションフレームワークとしても使い勝手が良いのですが、エレメントの管理に常に悩まされます。エレメント(テンプレート、テンプレート変数、チャンク、スニペット、プラグイン)は管理画面上から手軽に追加・編集可能な利点がある反面、DB上でコードが管理されているのでバージョン管理やコードの比較、バックアップがしづらい等、そのような問題がメンテ時の欠点として出てきます。(手軽さとメンテのしやすさはトレードオフの関係です)

そこで、コードを出力してファイルとして管理できるようにしました。ざっくりと書いた感じなので、調整が必要な場合もあるかも知れませんが、これによってメンテが少しでも楽になれば。。

コード

<?php

$dbname = 'DB名';
$dbhost = 'DBホスト(FQDN or IP)';
$dsn = 'mysql:dbname=' . $dbname . ';host=' . $dbhost;
$user = 'ユーザー名';
$password = 'パスワード';

$dbo = new PDO($dsn, $user, $password);
$dbo->query('set names UTF8');

$base_dir = dirname(__FILE__);

$prefix = 'modx_'; // MODxテーブルプレフィックス
$tables = [
        'site_snippets',
        'site_templates',
        'site_tmplvars',
        'site_modules',
        'site_plugins',
        'site_htmlsnippets',
];

foreach ($tables as $table) {
        $sql = 'select * from ' . $prefix . $table . ';';
        $my_dir = $base_dir . '/' . $table;
        mkdir ($my_dir, 0755);

        foreach ($dbo->query($sql)->fetchAll(PDO::FETCH_ASSOC) as $row) {
                $tmp = $row;
                unset($tmp['id']);
                switch ($table) {
                        case 'site_snippets':
                                $filen_base = '/' . str_replace(' ', '_', $tmp['name']);
                                file_put_contents($my_dir . $filen_base . '.json', json_encode($tmp));
                                file_put_contents($my_dir . $filen_base . '.php', $row['snippet']);
                                break;
                        case 'site_templates':
                                $filen_base = '/' . str_replace(' ', '_', $tmp['templatename']);
                                file_put_contents($my_dir . $filen_base . '.json', json_encode($tmp));
                                file_put_contents($my_dir . $filen_base . '.html', $row['content']);
                                break;
                        case 'site_tmplvars':
                                $filen_base = '/' . str_replace(' ', '_', $tmp['name']);
                                file_put_contents($my_dir . $filen_base . '.json', json_encode($tmp));
                                file_put_contents($my_dir . $filen_base . '.html', $row['elements']);
                                break;
                        case 'site_modules':
                                $filen_base = '/' . str_replace(' ', '_', $tmp['name']);
                                file_put_contents($my_dir . $filen_base . '.json', json_encode($tmp));
                                file_put_contents($my_dir . $filen_base . '.php', $row['modulecode']);
                                break;
                        case 'site_plugins':
                                $filen_base = '/' . str_replace(' ', '_', $tmp['name']);
                                file_put_contents($my_dir . $filen_base . '.json', json_encode($tmp));
                                file_put_contents($my_dir . $filen_base . '.php', $row['plugincode']);
                                break;
                        case 'site_htmlsnippets':
                                $filen_base = '/' . str_replace(' ', '_', $tmp['name']);
                                file_put_contents($my_dir . $filen_base . '.json', json_encode($tmp));
                                file_put_contents($my_dir . $filen_base . '.html', $row['snippet']);
                                break;
                }
        }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPでMySQLからデータを取得したときにinteger型が文字列になる問題

問題の始まり

とあるSPAな案件をやっていて、慣れているPHPでAPIサーバ作ってやろう!
と初めてのAPIを構築していたところ、データベースからのレスポンスが全部文字列で帰ってくる。

調べてみると、PDOでの解決方法はあれどmysqliはなかなか見つからずどうしたらいいんだ・・・
となったので備忘録がてらメモしておきます。

PDOの場合

PDO::ATTR_EMULATE_PREPARESFALSEにしましょう。
これはプリペアドステートメントをエミュレートモードで使用するというオプションで、デフォルトではTRUEになっています。

この場合、MySQLではなくドライバ側でエスケープ処理などが行われるのですが、
副作用でレスポンスがすべてStringで戻ってくるようになります。(型情報が失われる)

ただし、エミュレーションのほうが早い1ので、オフにする場合は計画的に。

mysqliの場合

MYSQLI_OPT_INT_AND_FLOAT_NATIVETRUEにしましょう。

というよりマニュアルにめっちゃ書いてあります。
コードを書くときはちゃんと公式マニュアルを読むようにしましょう・・・(します)

注意点

こちらもPDOもそうですが、サーバ側がmysqlndに対応していないといけません。
おそらくその辺りの兼ね合いでデフォルトでは無効になっているんでしょうね。


  1. ここここを参照 

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

COTOHA でキーワードの抽出 (PHP)

COTOHA API Portal の使用例です。

key_word.php
#! /usr/bin/php
<?php
// ------------------------------------------------------------------
//  key_word.php
//
//                      Feb/26/2020
//
// ------------------------------------------------------------------
include('Requests/library/Requests.php');
require_once './vendor/autoload.php';

// ------------------------------------------------------------------
include "get_config.php";
include "get_token.php";

// ------------------------------------------------------------------
fputs (STDERR,"*** 開始 ***\n");

Requests::register_autoloader();

$file_in = $argv[1];
echo    $file_in . "\n";

$doc = file_get_contents ($file_in);

$config = get_config_proc();
$access_token = get_token_proc($config);


$headers = array();
$headers['Content-Type'] = 'application/json';
$headers['Authorization'] = 'Bearer ' . $access_token;

$data = array();
$data['document'] = $doc;
$data['type'] = 'default';

$str_json = json_encode ($data);

$url_target = $config['url_base'] . 'v1/keyword';
$request = Requests::post($url_target, $headers, $str_json);

var_dump($request->status_code);

$json_string = $request->body;
$dict_aa = json_decode ($json_string,true);

foreach ($dict_aa['result'] as $key => $unit_aa)
    {
    $str_out = $unit_aa['form'] . "\t" . $unit_aa['score'];
    print($str_out . "\n");
    }

fputs (STDERR,"*** 終了 ***\n");

// ------------------------------------------------------------------
?>

get_config.php get_token.php はこちら
COTOHA API で構文解析 (PHP)

実行結果

$ ./key_word.php akai_rousoku.txt
*** 開始 ***
akai_rousoku.txt
int(200)
猿 135.52966
蝋燭  83.9601
花火  78.08584
亀 43.078
火 42.81965
*** 終了 ***
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

COTOHA で固有名詞の抽出 (PHP)

COTOHA API Portal の使用例です。

proper_noun.php
#! /usr/bin/php
<?php
// ------------------------------------------------------------------
//  proper_noun.php
//
//                      Feb/26/2020
//
// ------------------------------------------------------------------
include('Requests/library/Requests.php');
require_once './vendor/autoload.php';

// ------------------------------------------------------------------
include "get_config.php";
include "get_token.php";

// ------------------------------------------------------------------
fputs (STDERR,"*** 開始 ***\n");

Requests::register_autoloader();

$config = get_config_proc();
$access_token = get_token_proc($config);

// print($access_token . "\n");

$sentence = "特急はくたかで富山に向かいます。それから、金沢に行って、兼六園に行きます。";

$headers = array();
$headers['Content-Type'] = 'application/json';
$headers['Authorization'] = 'Bearer ' . $access_token;

$data = array();
$data['sentence'] = $sentence;
$data['type'] = 'default';

$str_json = json_encode ($data);

$url_target = $config['url_base'] . 'v1/ne';
$request = Requests::post($url_target, $headers, $str_json);

var_dump($request->status_code);

$json_string = $request->body;
$dict_aa = json_decode ($json_string,true);

foreach ($dict_aa['result'] as $key => $unit_aa)
    {
    print($unit_aa['form'] . "\n");
    }

fputs (STDERR,"*** 終了 ***\n");

// ------------------------------------------------------------------
?>

get_config.php get_token.php はこちら
COTOHA API で構文解析 (PHP)

実行結果

$ ./proper_noun.php
*** 開始 ***
int(200)
富山
金沢
兼六園
*** 終了 ***
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

COTOHA API で構文解析 (PHP)

COTOHA API Portal の使用例です。

parsing.php
#! /usr/bin/php
<?php
// ------------------------------------------------------------------
//  parsing.php
//
//                      Feb/26/2020
//
// ------------------------------------------------------------------
include('Requests/library/Requests.php');
require_once './vendor/autoload.php';

// ------------------------------------------------------------------
include "get_config.php";
include "get_token.php";

// ------------------------------------------------------------------
fputs (STDERR,"*** 開始 ***\n");

Requests::register_autoloader();

$config = get_config_proc();
$access_token = get_token_proc($config);

// print($access_token . "\n");

$sentence = "特急はくたか";

$headers = array();
$headers['Content-Type'] = 'application/json';
$headers['Authorization'] = 'Bearer ' . $access_token;

$data = array();
$data['sentence'] = $sentence;
$data['type'] = 'default';

$str_json = json_encode ($data);

$url_target = $config['url_base'] . 'v1/parse';
$request = Requests::post($url_target, $headers, $str_json);

var_dump($request->status_code);

$json_string = $request->body;
$dict_aa = json_decode ($json_string,true);

foreach ($dict_aa['result'] as $key => $unit_aa)
    {
    foreach ($unit_aa['tokens'] as $key => $token)
        {
        $str_out = $token['form'] . "\t" . $token['pos'];
        print($str_out . "\n");
        }
    }

fputs (STDERR,"*** 終了 ***\n");

// ------------------------------------------------------------------
?>
get_config.php
<?php
// ------------------------------------------------------------------
//  get_config.php
//
//                      Feb/26/2020
//
// ------------------------------------------------------------------
function get_config_proc()
{
    $dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
    $dotenv->load();

    $config = array ();

    $config['grantType'] = 'client_credentials';
    $config['clientId'] = getenv("CLIENT_ID");
    $config['clientSecret'] = getenv("CLIENT_SECRET");
    $config['url_base'] = getenv("DEVELOPER_API_BASE_URL");
    $config['url_publish'] = getenv("ACCESS_TOKEN_PUBLISH_URL");

    return $config;
}

// ------------------------------------------------------------------
?>
get_token.php
<?php
// ------------------------------------------------------------------
//  get_token.php
//
//                      Feb/26/2020
//
// ------------------------------------------------------------------
function get_token_proc($config)
{
    $str_json = json_encode ($config);
    $headers = array('Content-Type' => 'application/json');

    $request = Requests::post($config['url_publish'], $headers, $str_json);

//  var_dump($request->status_code);

    $json_string = $request->body;
    $dict_aa = json_decode ($json_string,true);

    $access_token = $dict_aa["access_token"];

    return $access_token;
}

// ------------------------------------------------------------------
?>

実行結果

$ ./parsing.php 
*** 開始 ***
int(200)
特急  名詞
は 動詞語幹
く 動詞接尾辞
たか  名詞
*** 終了 ***
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

カスタムフィールドの情報をWordPress REST APIで取得

カスタムフィールド作成

カスタムフィールドを作成する方法は以下の3つ

  • 既存機能を使う
  • functions.phpに書く
  • プラグインを使う

少し調べて試してみた結果、WordPress REST APIでカスタムフィールドを扱えてかつ難易度が低いものは「プラグインを使う」方法かなと思います。
というわけで今回はAdvanced Custom Fieldsというプラグインを使ってのカスタムフィールドの作り、その情報をACF to REST APIというプラグインを使いAPIで取得できるようにしていきます。

Advanced Custom Fields

デフォルトでもカスタムフィールドを作成できますが、Advanced Custom Fields(ACF)を使うと簡単にカスタムフィールドを作成することができるだけでなく、複雑な要件を満たすことも可能になるそうです。
Advanced Custom Fields

使い方

プラグインをインストールすると左メニューに「カスタムフィールド」ができます。
ここから「新規追加」をクリックします。
左メニュー

そうすると「フィールドグループ」と言うものが作成できます。
上部の「タイトルを追加」部分にフィールドグループの名前を付けましょう。
そしてその下の「フィールドを追加」ボタンをクリックしフィールドを作成します。
フィールドを追加

フィールドは色々設定がありますが、最低限「フィールドラベル」「フィールド名」「フィールドタイプ」を入力します。
フィールドを作成したら位置を設定します。これを設定することでどこでこのカスタムフィールドを表示するかを決定します。
位置

設定できたら投稿画面を見てみましょう。
作成したカスタムフィールドが表示されているはずです。

投稿

ACF to REST API

ACFで追加したカスタムフィールドはデフォルトでは取得出来ません。
(そもそもWordPress REST APIはデフォルトではカスタムフィールドのデータを取得できない。)
これを取得するために、ACF to REST APIというプラグインを導入します。
ACF to REST API

これを入れると投稿取得のAPIで

  "acf": {
    "test1": "xxxx"
  }

acfという項目が追加されます。

まとめ

Advanced Custom FieldsとACF to REST APIプラグインを導入して、カスタムフィールドの情報をWordPress REST APIで取得できるようにしました。
既存のWordPressソースをいじることなく簡単にできるのでおすすめです。

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

Laravel HomesteadでVagrant SSHがなかなかできなかった話

Railsを今までずっとやっていましたが、Laravelも学び始めた時にまず環境構築からだよなぁと思い、Qiita内の記事を参考にしながらComposerオンリーで作ってみたり、Homesteadを使ってみたりとしておりましたが、Homesteadで一日沼にハマってしまったので、こちらに備忘録的に書いておきたいと思います。
皆様の参考になれば幸いです。

とっても参照してお世話になった記事は 「こちら」からどうぞ!

バージョン情報

PC:Windows10 home 1903
Vagrant 2.2.7
Virtual Box 6.1.2
Composer 1.9.3
Laravel 6.15.1

Vagrant & Virtual Box

上記各々検索して出てきた公式サイトにてダウンロード可能です。

Homesatead

こちらでざっと環境開発に必要なプロセスを載せていきます。
1.ホームディレクトリにて

vagrant box add laravel/homestead

と入力してHomestead専用のVagrant Boxをインストールします。専用のVagrantfileも生成されます。
virtual Boxの番号を聞かれたら3でいいと思います。※この処理に時間がかかります。

2.ユーザーフォルダ直下やCフォルダ直下、デスクトップなどで任意の作業用フォルダを作ります。

3.作業用フォルダ内で

git clone https://github.com/laravel/homestead.git Homestead

と入力しHomesteadを召喚します。

4.Homeasteadフォルダもできるので、移動して

bash init.sh

と入力してHomeasteadの初期化を行います(これをやらないと不具合がでるらしい)Homeastead initialized等の文言が出てきたらOK

5.もしSSH鍵を生成していなかったら、

ssh-keygen

で作っておきましょう。エクスプローラーのユーザ/.ssh内にid_rsaとid_rsa.pubがあればできています。コマンドで

ls -la .ssh

とかでも見ることができます。

6.Homeasteadディレクトリに移動して、

vim homestead.yaml

で下記の用な感じに編集します。

--
ip: "192.168.10.10" #任意のIPアドレス
memory: 2048
cpus: 1
provider: virtualbox

authorize: ~/.ssh/id_rsa.pub

keys:
    - ~/.ssh/id_rsa

folders:
    - map: ~/app #任意の作業用フォルダ
      to: /home/vagrant/Code

sites:
    - map: homestead.test #任意のホスト名
      to: /home/vagrant/Code/Laravel/public #Laravelは作成するプロジェクト名、何でも良い

databases:
    - homestead

# blackfire:
#     - id: foo
#       token: bar
#       client-id: foo
#       client-token: bar

# ports:
#     - send: 50000
#       to: 5000
#     - send: 7777
#       to: 777
#       protocol: udp

7.vagrantを

vagrant up --provision #provision入れると不具合が起きにくいかと

で起動しましょう。

The specified host network collides with a non-hostonly network!
This will cause your specified IP to be inaccessible. Please change
the IP or name of your host only network so that it no longer matches that of
a bridged or non-hostonly network.

と出てきた場合は、Windows/System32/drivers/etc/hostsを管理者権限のあるエディタで開き、
ipと任意のホスト名を入力してあげましょう。

8.以上が完了したら、

vagrant ssh

を入力することでSSH接続が完了します。vagrant@homesteadというディレクトリ名に変わってると思います。

cd code

composer create-project laravel/laravel --prefer-dist ディレクトリ名 #この処理に時間がかかります

とすることで編集するプロジェクトが立ち上がり、編集が可能になります。
ちゃんとサーバーに接続できてるか確認するために、ipアドレスをブラウザに入力してみましょう。

あれ????できない????

Vagrant SSHができなかった・・・

何回やってもSSH接続ができない!そこで周りの猛者にきいてみたところ、
.ssh/configってなんやこれ?邪魔っぽくね?
というふうに見解をもらったので、すでに生成されているSSH鍵と一緒に右クリック!!!!
新しく鍵を作り直すと、
vagrant ssh
でやっと起動できました~!

image.png

まとめ

Homesteadを利用した環境構築において、
SSHまでやろうとしてもうまく行かない場合は、考えられる原因は
・Windows/System32/drivers/etc/hosts
・Homestead.yaml
・SSH鍵とその仲間.ssh/configファイル
です。ここに入力漏れがないかをみてみましょう。

ありがとうございました。

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

SendGridのテンプレート+PHPでメール送信

はじめに

SendGridのテンプレートを利用するメールの送信を実装したけど、公式のドキュメントが古くて参考にならないかつ思ったより参考記事が少なかったのでまとめました。

インストール

パッケージをComposerでインストール
https://github.com/sendgrid/sendgrid-php

composer.json
{
    "require": {
          "sendgrid/sendgrid": "~7"
    }
}
$ composer install

テンプレート作成

SendGridのコンソール画面からEmail API>Dynamic Templatesを選択
スクリーンショット 2020-02-20 17.55.17.png

Create a Dynamic Templateで新しいテンプレートを作成
こんな感じで作成されたテンプレートが表示されます
スクリーンショット 2020-02-20 18.02.28.png
赤で囲っているTemplate IDを後でコード内で呼び出します。

Add Versionからメールテンプレート本文を作成していきます。
今回はこんな感じに作成しました。
スクリーンショット 2020-02-20 18.32.42.png
{{}}で囲まれた部分に文字を埋め込むことができます。

テンプレートの詳しい作成方法はこちらを参考にどうぞ
テンプレートを適用して送信する(Dynamic Transactional Template編)

メールを送信する

以上で作成したテンプレートを使ってメールを送信していきます。

$email = new SendGrid\Mail\Mail();
$email->addTo('to_address@mail.com');
$email->setFrom('test@info.test', '送信元表示名');

// SendGridのコンソール上で作成したテンプレートのIDを設定
$email->setTemplateId($template_id);

// メールテンプレートに埋め込む文字列を設定する
$email->addDynamicTemplateData('name', '田中樹'); 
$email->addDynamicTemplateData('url', 'http://hoge.hoge');

// SendGridのAPIキーを設定
$sendgrid = new SendGrid($api_key);

// 送信
$sendgrid->send($email);

これで送信すると、以下のようにメールが届きます。

スクリーンショット 2020-02-20 18.56.20.png

今回は作成していませんが、{{}}で囲めばhtmlで作成したテンプレート内でも文字列の置き換えは反映されました。

手探りの実装になりましたが、もし間違いがありましたらご指摘ください。

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

COTOHA アクセストークンの取得 (PHP)

COTOHA API Portal の使用例です。

acess_token.php
#! /usr/bin/php
<?php
// ------------------------------------------------------------------
//  access_token.php
//
//                      Feb/26/2020
//
// ------------------------------------------------------------------
include('Requests/library/Requests.php');
require_once './vendor/autoload.php';

fputs (STDERR,"*** 開始 ***\n");

Requests::register_autoloader();

$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();

$client_id = getenv("CLIENT_ID");
$client_secret = getenv("CLIENT_SECRET");
$url_base = getenv("DEVELOPER_API_BASE_URL");
$url_publish = getenv("ACCESS_TOKEN_PUBLISH_URL");

$data = array('grantType' => 'client_credentials','clientId' => $client_id,
        'clientSecret' => $client_secret);
$str_json = json_encode ($data);
$headers = array('Content-Type' => 'application/json');

$request = Requests::post($url_publish, $headers, $str_json);

var_dump($request->status_code);

print("-----------\n");
var_dump($request->body);
print("-----------\n");

$json_string = $request->body;
$dict_aa = json_decode ($json_string,true);
print($dict_aa["access_token"] . "\n");

fputs (STDERR,"*** 終了 ***\n");

// ------------------------------------------------------------------
?>

実行結果

$ ./acess_token.php
*** 開始 ***
int(201)
-----------
string(249) "
          {
            "access_token": "7Zj26srl557J3ffR********", 
            "token_type": "bearer",
            "expires_in": "86399" ,
            "scope": "" ,    
            "issued_at": "1582683782964"           
           }
        "
-----------
7Zj26srl557J3ffRGfbdWYAbCT8U
*** 終了 ***
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

xDebug使ってたらマジカル定数__FILE__や__DIR__でエラーや期待しない動作をする

vscodeでxDebugつかってデバッグしてるときにハマったので備忘録。
間違いなどあれば教えて下さい:bow_tone1:

現象

// ↓がtrueになるべきケースでもfalseしか返さない。
if ( file_exists( __DIR__ . '/hoge.php') ) {
}

原因

参考記事によれば、xDebugがデバッグ時にマジカル定数を動的に生成しているため。
デバッガを噛まさなければ、この問題は起きない。

__FILE__xdebug://debug-evalに評価されるし、
__DIR__xdebug:に評価される。
dirname(__FILE__)xdebug:に評価される。
dirname(__DIR__) だと、期待するパスに評価される。

dirname(__DIR__)以外の解決方法としては、先に$dir = __DIR__;と代入してしまって、動的生成の影響を受けないようにする。

ただ、dirname(__DIR__)にしても、$dir = __DIR__;にしても、コードをパット見たところ冗長な感じはするし、デバッガの都合がコードの入り込むのは違和感しかないので、好きではないなー。

参考

php - xDebug weird __DIR__ constant - Stack Overflow

php - Uncaught exception 'ErrorException' in xdebug://debug-eval - Stack Overflow

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

[Laravel] Collection の順番を逆にしたいけどキーが邪魔になるとき

Laravel の Collection は reverse() メソッドによって逆順に並び替えることができます。
しかし以下のようにキーが付与(*1)されてしまうので、思い通りの比較ができないことがあります。

$collection = collect(['a', 'b', 'c', 'd', 'e']);

$reversed = $collection->reverse();
/*
    [
        4 => 'e',
        3 => 'd',
        2 => 'c',
        1 => 'b',
        0 => 'a',
    ]
*/

$otherCollection = collect(['e', 'd', 'c', 'b', 'a']);

echo $otherCollection === $reversed;
// false

そうじゃないんだよ、欲しいのは ['e', 'd', 'c', 'b', 'a'] なんだよって時は
values() メソッドでキーを削除(*2)しちゃいましょう。

$collection = collect(['a', 'b', 'c', 'd', 'e']);

$reversed = $collection->reverse()->values();
/*
    ['e', 'd', 'c', 'b', 'a']
*/

$otherCollection = collect(['e', 'd', 'c', 'b', 'a']);

echo $otherCollection === $reversed;
// true

*1 「付与」→正確には「保持」
*2 「削除」→正確には「リセット」
説明は次の項にて

なぜなのか?

前項で使った「付与される」という表現は正確ではなく、 Laravel のドキュメントにもある通りキーが保持された結果として、「新たにキーが付与された」ように見えているだけです。
コレクション

前提としてPHPでは、全ての配列は以下のようにキーを持っています。

$array = ['a', 'b', 'c', 'd', 'e'];
/*
    [
        0 => 'a',
        1 => 'b',
        2 => 'c',
        3 => 'd',
        4 => 'e',
    ]
*/

さて、 Collection の reverse() では PHP の array_reverse() を利用していますが、
第2引数に true を指定しているのにご注目?

    public function reverse()
    {
        return new static(array_reverse($this->items, true));
    }

array_reverse()の第2引数はpreserve_keys「キーを保持」するパラメーターです。
array_reverse

PHP の配列の世界で表現するとこんな感じ。

$array = ['a', 'b', 'c', 'd', 'e'];
$otherArray = ['e', 'd', 'c', 'b', 'a'];
/*
    [
        0 => 'e',
        1 => 'd',
        2 => 'c',
        3 => 'b',
        4 => 'a',
    ]
*/

$reversed = array_reverse($array, true);
/*
    [
        4 => 'e',
        3 => 'd',
        2 => 'c',
        1 => 'b',
        0 => 'a',
    ]
*/

echo $otherArray === $reversed;
// false
// キーが一致しないので別の配列

Laravel のvalues()では、array_values()を呼び出しています。

    public function values()
    {
        return new static(array_values($this->items));
    }

array_values() は配列の値を取り出してキーを振り直すメソッドなので、以下のように欲しい配列を取得することができるんですね。
array_values

$array = ['a', 'b', 'c', 'd', 'e'];
$otherArray = ['e', 'd', 'c', 'b', 'a'];

$reversed = array_values(array_reverse($array, true));
/*
    [
        0 => 'e',
        1 => 'd',
        2 => 'c',
        3 => 'b',
        4 => 'a',
    ]
*/

echo $otherArray === $reversed;
// true

// 配列でやるなら単純にこれでもいい
$reversed2 = array_reverse($array, false);
/*
    [
        0 => 'e',
        1 => 'd',
        2 => 'c',
        3 => 'b',
        4 => 'a',
    ]
*/

echo $otherArray === $reversed2;
// true
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Eloquentモデルのクラス名から主キーを取得する

はじめに

既存のDB構成の都合上主キー名が異なるテーブルで条件付きでID一覧をクラスごとに取ろうとしたときにいい方法に出会ったのでそのメモ

愚直な方法

クラス名指定で書くと似たような箇所も多く追加でいちいちcaseを増やさないといけなく面倒・・・

// それぞれ主キー名が異なる類似したモデル
use App\Hoge;
use App\Fuga;

function scopedIds(string $className): array
{
    switch ($className) {
        case Hoge::class:
            return Hoge::scope()->pluck('hoge_id');
        case Fuga::class:
            return Fuga::scope()->pluck('fuga_id');
    }
}

EloquentモデルのgetKeyNameでやってみる

https://laravel.com/api/6.x/Illuminate/Database/Eloquent/Model.html#method_getKeyName
EloquentモデルのメソッドとしてgetKeyNameという主キー名を取得するものがあり、これ活用するとシンプルに済む

function scopedIds(string $className): array
{
    $primaryKey = (new $className())->getKeyName();
    return $className::scope()->pluck($primaryKey);
}

終わりに

調べてみるとまだまだ便利なメソッドが提供されているので、複雑なDB構造と戦っている時にドキュメントを覗くといいやり方があったりするので、参考にできそうな感じ

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

Laravel Horizonのfailed_jobsテーブルを生SQL(PostgreSQL)で追加してみる

はじめに

Laravel Horizon導入時に失敗したjobを溜め込むfailed_jobsテーブルが必要ですが、migrateがLaravelとは別で機能しているため、自前でテーブル構成を定義したときの話です

環境

name ver
PHP 7.3
Laravel 6.5
PostgreSQL 10.6

Laravelでマイグレーションした場合のテーブル構造

既存でPostgreSQLを使ってHorizonを導入しているプロジェクトがあったのでテーブルをみてみるとこんな感じだった

hoge=> \d+ failed_jobs
                                                              Table "public.failed_jobs"
   Column   |              Type              | Collation | Nullable |                 Default                 | Storage  | Stats target | Description
------------+--------------------------------+-----------+----------+-----------------------------------------+----------+--------------+-------------
 id         | bigint                         |           | not null | nextval('failed_jobs_id_seq'::regclass) | plain    |              |
 connection | text                           |           | not null |                                         | extended |              |
 queue      | text                           |           | not null |                                         | extended |              |
 payload    | text                           |           | not null |                                         | extended |              |
 exception  | text                           |           | not null |                                         | extended |              |
 failed_at  | timestamp(0) without time zone |           | not null | CURRENT_TIMESTAMP                       | plain    |              |
Indexes:
    "failed_jobs_pkey" PRIMARY KEY, btree (id)

念の為新規でLaravelの環境を用意してチュートリアルどおり入れてみても同様なのでこの構成で大丈夫そう
https://readouble.com/laravel/6.x/ja/queues.html

実行したSQL

上のテーブル構造から以下のSQLを実行で問題なく作成できた

CREATE TABLE failed_jobs (
    id         BIGSERIAL PRIMARY KEY,
    connection TEXT NOT NULL,
    queue      TEXT NOT NULL,
    payload    TEXT NOT NULL,
    exception  TEXT NOT NULL,
    failed_at  TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

おわりに

artisanコマンドは便利だけど、やっぱり内部実装を理解してから使わないと混乱するので、実験って大事

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