「PHP」カテゴリーアーカイブ

【cakePHP3】bakeで自動生成されるリンクは動詞と名詞を別々に__()に翻訳させるといいですよ

最近、cakePHP3を使っています。
しばらくfuelPHPとか、あと名前も忘れましたがいくつかPHPフレームワーク使っていました。
しかしcakePHPの規約たくさん、でも覚えてしまえば分かりやすいぬるめのお湯的な感覚が忘れがたく、PHP5.2を捨ててクラスのauto loadとチェインによるSQL生成さえ対応してくれればいつでも戻ってくるつもりでした。そしたら、いつの間にかcakePHP3になってそれらも実装されているし、いろいろ変わっているではありませんか。

しばらく使ってみた感想は、正統な進化で慣れてくるとやはり使いやすいです。しかし、ドキュメントの劣化がひどいです。かなり公式が分かりづらいです・・・。

さて、今日はbakeで自動生成されるView画面のリンク名を日本語に翻訳していく時の簡単なテクニックです。

↓画像のように日本語化したいと思います。

とコマンドを打てばtexturesテーブルを元にindex,view,edit,addの各画面を勝手に作ってくれる、モックアップに超便利な機能です。
生成した画面の左のメニューなど、ソースでは
といった感じになっていると思いますので、翻訳ファイル(src/Locale/ja/default.po)は
が必要ですね。
List ..以外にもAdd ..、New …などあり、これだと翻訳が必要になる文章が多くなりますので
とViewを書き換えることを提案します。
を用意したら “Textures一覧”と翻訳されます。
Texturesの翻訳も用意したらちゃんと「画像一覧」と全文翻訳されます。この方法だとdefault.poの記述はかなり少なく済みます。
既に生成された全ファイルに対して一気に変えたいという場合は
の正規表現でどうぞ。
あれ、この内容、前にもどこかに書きましたっけ??
あとは生成するテンプレート自体を変えるやり方とか、翻訳のもう少し詳しいやり方とか気が向いたら書きます。

【FuelPHP】追加日(created_at)を指定して追加する

ORMモデルの中で

 

という設定をして追加日、更新日を自動設定していることが多いと思いますが、これだと追加日(created_at)を特定の日にしようとしても自動的に追加の日になってしまいます。

あるコントローラーの中だけobserverを解除して日時を指定したい場合は次のようにします。

 

slenium2で大量のデータと写真をCSVでフォームから入力する[php]

今回はテストツールSleniumでWEBに用意したフォームにデータ入力していきたいと思います。

まずSleniumをダウンロードします。Sleniumは役割ごとにSleniumRCとかSleniumIDEとかいろいろ分かれていて最初は何をダウンロードしていいか分からず難しいですね。
今はRCとかIDEは使わず、Selenium WebDriverが最新みたいですが、Slenium2と言ったほうが分かりやすい気がします。
私はPHPでテストを書きたかったので、Sleniumクライアントは今もメンテが続いているfacebook/php-webdriverを使うことにしました。

インストールはcompserを使うのがいいです。

というcomposer.jsonを作って、

を実行すれば必要なファイルがダウンロードされます。composerがない場合は

で取得してください。

sleniumのローカルサーバーも立ち上げておきましょうね、http://selenium-release.storage.googleapis.com/index.htmlから最新版のselenium-server-standalone-x.xx.x.jarファイルをダウンロードして起動しておきます。

と打てば起動しますので、テスト中は立ち上げっぱなしにしといてください。

ではPHPでテストを書きます。

firefoxが立ち上がってgoogle検索されます。

ではURLを自分のWEBフォームに変えて、データをCSVから呼び出し繰り返し実行するようにします。

私の環境はMacなのでCSV読み込みで文字化けしたため事前にutf-8にCSVを変換しました。さらに改行が読み込まれなかったのでauto_detect_line_endingsをtrueにしていますが必要ない場合もあるでしょう。

でcsvファイルを読み込んでいます。得られたデータを次々にフォームに入れていきます。

こんな感じでファイル名からファイルアップロードもできます。

いけましたか?たぶん、最低限これだけでいけると思うのですが、いけてなかったら教えて下さい。さくさくデータが自動入力されるのを見ると感動的ですよ。

それでは充実したテストライフを!

 

 

 

 

【cakePHP】配列を組み替える便利なHashクラス

cakePHP使っててうれしいのが、Hashクラスが組み込まれていることです。

これはとっても便利なので、他のフレームワークを使う時でももし同等のものがなければコピーして使おうかと思っています。

サンプルコード

いくつか簡単な例をあげます。

このような配列があるとして、

4番目のユーザーの名前を取り出したいとき

Result:

Userの下の配列は数値キーで0から始まっているので4番目を指定するには3になります。説明無用とは思いますが念のため。

idが2のユーザーの名前を取り出したいとき

[配列名=配列値]の書式で条件式を書けます。

Result:

配列名がなければ配列番号でもいけます

Result:

Hashクラスのマッチャで使える記号:

‘=’
‘!=’
‘>’
‘<‘
‘>=’
‘<=’

等号は==でなく=なので注意してください。

配列のキーをidにして必要なデータのみの配列を作りたい時

Result:

このようにすっきりした配列を作成できます。リンクリストなどを作るのに活躍します。

条件式で指定したデータの配列を生成する

combineとマッチャを組み合わせて使用するときに注意しないといけないのが、第2引数と第3引数、両方にマッチャを指定しないといけないことです。キーと値の数が合わないとfalseが返ってきます。

Result:

グループIDでグルーピングしたユーザー配列を生成する

2次元配列を作るにはcombineに引数を追加します。

Result:

group_idでユーザーを分けることが出来ましたね。

複雑な階層の多次元配列を扱う

不特定のキーを表すのに{n}と{s}があり、nが数値キー、sは文字列キーに対応しています。Hashパス構文の中に何個でも出現して構いません。

Result:

キャラクターの持つアイテムリストができました。idをキーとすることで重複は省かれています。

sptinrfの結果を値に入れる

Hash::formatを使えばsprintfの結果を取り出せます。

Result:

これをHash::combineでやるときには第3引数を配列にして、1番目にフォーマット文字列を入れます。

Result:

 

ほかにもいろいろ便利ですが

文字列を生成したり、配列に値を加えたり削除したり、非常にいろんなことができますが、抽出系に絞って書いてみました。

cakePHPの公式ドキュメント「Hash」をみれば全部書いてますが、サンプルが少ないのでちょっと分かりにくいかもと思うところもあります。

これを参考に、配列を自由に扱えるようになるとデータの扱いもぐっと幅がでてくることでしょう。

最後に、進撃の巨人のキャラクター名をサンプルに使ったのは深い意味はないのでその辺のツッコミは無用でお願いします。

【PHP】Filter関数を使ってみる

こんにちわ、こんばんわ。最近はKANA-BOONをたまに聴きます。今日はフルドライブ聴いてます。こういうシンプルで若いなって感じのたまに聴くといいのぉって思います。

さて、以下のオーダーを頂きました。

ひらがな、カタカナ(「-」を除く)、漢字、英数字のみを使い記号、スペースは除く。

こういうの、今まで何回も作ってきた気もするんですが、いつも忘れてしまうんですよね。思いつくのは
・preg_replaceを使ってUTF8文字コード\x000とかなんとかで変換かける
・mb_convert_kanaを使って全角を半角にしたうえでなんとかする

とりあえずmb_convert_kana使ってみますか

あとは記号・空白や改行ですね。ASCII文字コードで記号の16進コードを確認して記号・空白を抽出する正規表現は[\\x0-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\x7f]だと分かりました。すいません、もっと簡単かと思いましたけど思ったより記号がコード表の中で分散していたのでコードが長くなっちゃいました。
あと本当はね、、引用符(wikipedia)の半角文字も考慮しないといけないんだよね・・・「”」じゃなくて「”」とか。ブラウザだと同じに見えてるかもしれないけど、最初のが&#x22;で後のは&#x201D;だからね。面倒だ〜;;後で考えます。

うん、できた。

でもこれで終わると面白く無いのでもっと簡単にできないか調べてみると、PHP5.2からFilter関数(PHPマニュアル)というのがあるのがわかりました。

メールアドレスが有効かどうか調べて、メールアドレス部分だけ取り出すとか簡単です。次のコードでメールアドレスが取り出せます。

第3引数に定数じゃなくて配列を渡すこともできます。
数値が0~10の整数の範囲か調べて、無効なら0を返すにはこうなります。

min_rangeとかfragsのFILTER_FLAG_ALLOW_OCTALとかは、FILTER_VALIDATE_INTフィルタで許可されているオプションです。
おぉ、、なんかフレームワークがやるような処理を組み込んでる。さすがPHP!おせっかいさん!憎いぜ!これなら最初の関数も簡単にできるかも!

・・・できませんでした。デフォルトで用意されている除去フィルタの一覧をみると、最低限のものしかない印象。

自分で登録したコールバック関数使ってみます。

できたできた。引用符の問題については、Filter関数でも解決してくれないぽくて疲れたのでまた今度。[\\x0-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\x7f“”‘’]でいけるかと思ったら、他の文字が壊れたりしてハマっちゃったんですよ。昔やった時はstr_replaceとかで一文字づつ消した気がしますよ。なんかいい方法があれば教えて下さい。

GETやPOSTをフィルタリングしてくれるfilter_input/filter_input_arrayなんかでも同じパラメータで使えるので、使い回しを考えるとFilter関数いいかもしれません。

クローリングで使うXPathのサンプル

XPathというのはXPathを扱うための言語構文です。SQLや正規表現のように、PHPをはじめ多くの言語で使うことができる、すばらしく便利な言語です。これを使えば、単にHTML内の特定の文字列を取り出すだけでなく、文字列関数を使った加工まで出来てしまいます。

クローリングするのにわりと使うであろうXPathをいくつか書いてみます。

PHPでXPathを扱うにはPHPコアに含まれるDOMXPathクラスを使う方法、SimpleXMLを使う方法があります。PHPのXPathは1.0の対応です。2.0にはまだ対応していないようです。

HTMLをXMLとして読み込んで使うやり方

いろいろ試してみて、安定した方法が分かってきました。最近はDOMXPathをよく使っています。文字化け対策でutf8のHTMLをHTML-ENTITIESにすると良いようです。

「次へ」もしくは「Next」と書かれたリンクのURLを取得する

 2番目以降のliを取り出す

 取り出した値を好きなPHPの関数で処理する

最初に名前空間に登録して使います。

クラスを使う場合は、staticで静的関数にしないと使えません。

のように使えます。

テーブルの行の中でTHヘッダをみて好きな行のTDを取得する

リンクURLの中に「*- 」が含まれていた場合は後半のみ取得、含まれていない場合はそのまま取得する

他のサンプル

AutoPagerize WikiのXPath Cookbook

MicrosoftDeveloperNetwork XPathの例

wikipediaのXPathのページ(サンプルではないけど分かりやすいので最初に読むといい)

 

【cakePHP】繰り返しrequestActionを呼び出すのをApp::usesにしたらメモリ使用量が抑えられた

cakePHPのシェルコマンドモードから繰り返しrequestActionを呼び出すコードを実行すると、2000回くらい繰り返したところでメモリオーバーで停止していたのを解決しました。

PHPバージョンが5.2なもので、バージョンアップすればガーベッジコレクションが効いてなんとかなるかも(PHP マニュアル >機能 >ガベージコレクション)、とも思ったのですが、お客様のサーバーだし、そもそもメモリーを使い続けるのがおかしいのでなんとかしてみます。

まず、メモリ使用量の計測

結果:

どんどんメモリ使ってますね。requestActionがかなりメモリを消費する関数だって事は分かっているので、ここをもう少し低レベルなものに置き換えます。単純にControllerクラスを呼び出すのがいいでしょうが、cakePHPにはApp::usesを使った便利な呼び出しがあります。

改善された!ちょっとづつ増えていますが、16Mくらいで安定して、増え続けるという事はありませんでした。

最初にApp::uses(“ItemsController”, “Controller”);で使用する事を宣言しておきます。App::importでもいいのですが、cakePHP2ではusesの方が使用する時だけ呼び出すのでいいっぽいです。

使用する時は$ItemsController = new ItemsController;で宣言して、いつも通り$ItemsController->action()でいいのですが、これだとbeforeFilterが実行されません。
$ItemsController->constructClasses();
$ItemsController->startupProcess();
をクラスの宣言直後に行う事で、初期化されるようになりました。

コントローラーの変数は直接操作できるので、$ItemsController->request->params[‘requested’] = 1のようにリクエスト変数をいじってrequest_actionと同じパラメータにすることもできます。

【cakePHP】.htaccessでmod_rewriteを使いつつ特定のURLをBASIC認証なしにする

毎日スパムコメントを捨てています、自宅プログラマです。

さくらのレンタルサーバーってCGI版PHPなんで、CakePHPの認証モジュールを使えないんですよねー。そういうわけで、apacheでBASIC認証かけていました。最初の.htaccessはこうです。

AuthUserFileは自分で作ってくださいね。bakerattaというのはfoobarやhogeと同じようなメタ構文変数ってやつです。

How to make Basic Auth exclude a rewritten URL
をみて

をやるとmedicine以下の時だけ$_SERVER[‘REDIRECT_noauth’]という変数ができてました。$_ENVにも同じものが。なんだ、これ、おもろー。なんでREDIRECT_がつくんだろ。$_SERVER[‘REDIRECT_REDIRECT_noauth’]ってのもできるし。そっか、URLが書き換わるたびにhtaccessを評価するんですね。
って、最初、環境変数がセットされているか確認の仕方が分からず、ここまででかなり苦労しました。呼び出したPHPでphpinfo()を実行すればapacheの一時変数も$_SERVERに入るんで、これで足がかりができました。
phpinfoの結果

んで、それでもうまくいかず、いろいろやっているうちに結局mod_rewriteの環境変数使わなくてもSetEnvIfだけでいけました。

Satisfy にanyを設定することにより、ユーザー認証だけでなくホスト制限もみてくれるようになります。
これで通常はBASIC認証かけつつ、medicineディレクトリ(と、そこから呼び出されているcss/imgディレクトリ)以下がBASIC認証対象外になりました。

ポイントは、Rewrite書き換え前と書き換え後、2つのURL両方を書いておくことです。

SetEnvIfを使ってBASIC認証解除したいURLを加えていけばいいので分かりいいですね。

## 2016/03/16 追記
img/x.gifのようなファイルをリクエストしているにも関わらずファイルがみつからない404の時にもBASIC認証がでていたので
SetEnvIf Request_URI “/webroot/index.php” noauth
を追記しました。
ファイルがない場合、cakePHPはwebroot/index.phpにリダイレクトするのでここも許可対象に入れたということです。一見すべてのアクセスが許可されたように思えますが、URLが書き換えられる前もチェックされるのでこれでいいのだ!
あと、特定のコントローラだけBASIC認証かける時とかはPHPで処理した方が簡単です。
HappyQuality – [CakePHP][PHP]コンポーネントを利用せずにベーシック認証を実装する

【PHP】mb_strimwidthの使い方

最近、蛍が飛んでるようです。以前から家の裏とかもちょこちょこ蛍が飛んでたりしてたんですが、自分が田舎に帰ってきた9年ぐらい前から、近くの川で蛍で本格的に乱舞するようになってます。


さて、PHPって、本当に親切な関数がたくさんあるんですが、mb_strimwidthもこんな親切でいいの!と思う関数のひとつですよね。

記事をリストに並べたりした時に、文字数を短く丸めたいときに好きな文字数で丸める上に「…」とか「(続く)」とか、丸めた時だけお尻に文字をつけられます。この処理が一行で出来るなんて便利!

パラメータは順番に

str 丸めたい文字列。
start 開始位置のオフセット。文字列の始めからの文字数 (最初の文字は 0) です。
width 丸める幅。
trimmarker 丸めた後にその文字列の最後に追加される文字列。
encoding encoding パラメータには文字エンコーディングを指定します。省略した場合は、 内部文字エンコーディングを使用します。

となっています。

 

実行結果:

ただ、mb_系のマルチバイト関数全体がそうですがちょっと使いづらいところもあり、自前で処理している人も多いとか。でもせっかくPHPの中にあるんなら、そっち使いたいです、わたしは。

mb_strimwidthのはまりポイントは2つ。

1.第3引数のwidthは文字数でもバイト数でもなく文字幅。

バイト数だったら、UTF-8の全角文字は3バイトになるところですがどの文字エンコードでも全角は2です。ここを間違うと意図したところで切れなくて困ります。

英数、半角カタカナは1と数えます。見た目の大きさを基準にしているということです。ただ、タブ文字とか改行も1と数えるので、単純に見た目とも言えなかったり。この辺は、プログラマなら分かるよね?…という目配せ的なアレですね。

2.第4引数のtrimmarkerの文字幅もwidthに含まれる

と書くと分かりやすいでしょうか、手順から考えると。

3.第5引数のencodingは必ず指定する、絶対。

とうとう、最後の第5引数まできちゃいました。マルチバイト関数の文字エンコーディング指定は分かる人はいちいち指定する必要もないんでしょうが、ね。

encodingは指定しなければ内部文字エンコーディングになるんですが、指定しておけば間違いないです。ここを間違った文字エンコーディングにすると文字化けします。

ちなみにmb_internal_encodingで事前に文字エンコーディングを指定してやるのも有効です。

ここまでやって、まだ不安だったので本当に文字化けしないか調べる時に使ったコード

これをcloud9で文字列とか文字幅とかいろいろ変えてみて、バイナリレベルでみてみたのですが、変な事は起きませんでした。

参考:指定した文字数で文字列をまるめるPHPの関数 mb_strimwidth で、第4引数に「文字列をまるめた後に付加する文字列を指定」する際、色々気を付けないと文字化けるよ、というお話。

 

【PHP】SimpleXMLで取得したノード以下のテキストを取得

ノード以下のテキストを取得するにはDOMNodeにTextContentという便利なプロパティがありますので、いったんDOMに変換して取得するのがいいように思います。

実行すると
bold text

とタグのないテキストだけの文字列が出力されます。