PHPの開発メモ(Tips)ITエンジニアの四方山話PHP、Perl、html、xmlの開発メモ、その他色々書いています。PHPコーディングfopenでインターネット上のファイル内容を取得できない時2018年12月14日PHPのfopen関数は、ファイル名にURLを指定するとURLの内容を取得できます。ところが、セキュリティ設定が厳しいレンタルサーバーではこの機能がオフになっていることがあります。外部の悪意あるファイルを読み込まないとも限らないからです。【ネットビジネス便利ツール】が販売しているツールではユーザー様に対するお知らせをこちらのサーバーにアップロード、ユーザー様がインストールなさったツールからfopen関数でお知らせを取得して表示しています。バージョンアップのお知らせや大切な事をお知らせするのに使っています。メールでもお送りしますが、アドレスが変わった場合でも見られるようにしています。ファイル内容もただのテキストでソースコードは一切ないファイルです。本当に悪さをしようと思ったら、お知らせなんかよりツール内部に入れるよね普通。ツールの機能に直接影響するわけではありませんが、やはりきちんと取得できた方がいいので改善しました。fopen関数でURLが取得できない場合は、【allow_url_fopen】が【Off】になっています。php.iniで変更できます。On以前はソースからも変更できたようです。不特定多数に配るツールなので、php.iniを変更してもらう説明は面倒です。fopen関数の代わりにcURL関数を使うことにしました。curl_exec($objCH);curl_close($objCH);他にも少々修正を加えて、【PayPalオートメール】のバージョンアップをしました。コメントTop↑PHPコーディングPHPの三項演算子2018年11月14日プログラミング言語によらず、三項演算子は使ったことがないのですが、使ってみようかと調べてみました。三項演算子って開発プロジェクトでも使ったことがないんですよね。わかりにくいから使わない方針だったのでしょうか。一度もお目にかかったことがない気がします。使ったことがない、つまり使う習慣がない、つまりいつまで経ってもパット見てわかるようにならないので、ますます使わない、という循環になっていました。存在する場合はそのまま、というコーディング(デフォルト値の設定)をできるだけ短く書きたいのです。$c;)$bがtrueなら$bを、falseなら$cを$aに代入します。このソースは$bが存在しない場合Noticeが発生してしまいます。$c;$bがtrueなら$bを、存在しないかfalseなら$cを$aに代入します。これでいけるじゃないと思ったのですが、この三項演算子はPHP7から導入されました。PHP5では動きません。自分で使うのならPHP7固定で良いのですが、不特定多数の方が使われるので、できればPHP5でも動くようにしたいです。"";$bが存在していてnullでないなら$bを、存在していないかnullなら空文字を$aに代入ううん、実際には深い配列もあるし、短くないなぁ。書き直す手間を考えると使うメリットはほとんどないので、使わないことにしました。変数と配列の宣言を完璧にできれば悩むこともないのですけどね。できるだけ宣言して、忘れてもPHPは動くので、PHPの試用に少し甘えることにしました。使わないことにしましたが、勉強になりました。使う機会がなければ次に使おうとした時はきれいに忘れているでしょう。ManualコメントTop↑SQLMySQLがガラリと変わっていました2018年10月22日まだ完全移行ではありませんが、一応【ネットビジネス便利ツール】のSSL化とSQLサーバーの文字コード変換が終わりました。動いていない箇所の修正には時間がかかるので、とりあえず非SSLで動かします。何度もテストをするのは面倒なので、ページそのものをUTF-8へ、html5へ変更しました。PHPもバージョン5から7へ移行しています。その関係で久々にMySQLの部分のPHPのソースを触ることになりました。PHP7ではmysqlが使えなくなっています。何かで読んで知ってはいましたが、そうですね、修正しなくてはいけませんね。調べたらmysqliかPDOを使うことになるとのこと。mysqliを使うことにしました。改良版拡張モジュールここがわかりやすかったです。意外にハマってしまったのが、文字コードです。MySQLもWebページもUTF-8にしているのに化けてしました。古いmysqlのソースを見ていると文字コードを指定していました。言えばそうでした(このブログでも書いていました・・・MySQLの文字化け)。"UTF8");です。UTF-8ではなく、UTF8で指定します。テスト環境で色々触っているのですが、完全に本番と同じではないことでエラーになったり、バグも見つけてしまったりとなかなか前に進めません。自分が何をやっているのか、わからなくなりそうです。さあ、また明日続きをやろう。別のソフト開発に取り掛かっています。今度のソフトはPHPでコーディングしているので、かなり楽に、楽しんでコーディングできます。PHPとのお付き合いもかなり長いですが、まだまだ知らないことだらけです。前に派遣で行っていた会社で学んだPHPが私のPHPスキルの基盤になっています。その会社で使っていなかった機能や目にしなかった機能はまだまだ沢山あり、毎日が勉強です。時にはなかなな理解できず苦しいこともありますが、分からなかった事、できなかった事ができるようになるのは楽しい事です。PHPでは未定義変数や未定義配列インデックスから値を読もうとすると、Noticeが発生します。致命的ではないので、何事もなかったように続けて処理ができるため、今まではいつか何とかしようと先延ばしにしていましたが、今回良い機会かと思い、潰すことにしました。今コーディングしているフォームからPOSTされたデータについてNoticeを潰してみました。その過程で新しく【filter_input】と【filter_var】関数を知りました。$_POST['name'];とやると、Noticeが発生します。【isset】関数などで、存在するかどうかをチェックしてから変数に代入しなくてはいけないのですが、これを一発でやってくれる関数が【filter_input】なんだそうです。'name');で、値があればその値を、未定義ならNullを返してくれます。Noticeを発生させずに値を読めるわけです。$_POSTの他に、$_GET、$_COOKIE、$_SERVER、$_ENVで使えます。Manualこの関数で、一番使いたいと思ったのが、メールアドレスチェックです。【filter_input】関数の第3引数でフィルタを渡すと、形式チェックをしてくれるというのです。FILTER_VALIDATE_EMAIL);メールアドレスを正規表現でチェックするのは、とてつもなく大変なんだそうで・・・ビジネス的には不可能ですね(元が取れないので)。いうことで、【filter_input】関数のお世話になろうと思ったのですが、この関数は多次元配列が扱えないそうなんです。ううん、不細工なソースになるけど仕方ないかなと思ったら、【filter_var】関数でもメールアドレスチェックができるのだそうです。FILTER_VALIDATE_EMAIL);メールアドレスでなければFalseを返してきます。沿った形式かどうかをチェックするので、ドコモの【docomo.@example.com】形式ではFalseになります。今回はこれで十分です。沿ったアドレスを入力して貰えばいいだけなので、十分です。コメントTop↑PHPコーディングセッション導入で更にセキュアに2013年07月03日セッションを導入し、システムをよりセキュアにすることにしました。セッションの役割、機能を学ぶには、こちらのサイトが役立ちます。基本的な使い方がわかります。触れられているだけのセッションクッキーについては、クッキーとセッション管理を読むとわかります。これらを踏まえて、システムにログイン後、セッションを使ってユーザ認証するソースをコーディングです。【session_start();】をコールすると、クッキーにセッションIDがセットされます。クッキーが使えない環境もあると思いますが、URLにセッション情報を含めるのはいかがなものかと思うので、今回は使えない環境は無視です。セットされたクッキーのセッションIDとサーバーにあるセッションIDが同じかどうかで判断します。今まで使ってた認証も残しているので、2重3重のチェックが走ります。【PayPal毎度ありがとうメール】をご購入いただいたことがご縁で、WordPressの改変を頼まれました。楽しもう!を見て改変したのだけれど、うまくいかないということでした。追加したいのは、コメントした人の名前です。説明を読む限り、そんなに難しくなさそうだと思い、やってみることにしました。ところが、なぜかうまくいかないのです。最後のコメントだけ、名前が取得できないのです。ループが最後まで回っていないのでしょうか・・・それともデータベースがおかしい?WordPressの件はできない旨をお伝えして、改変は取りやめにしていただきました。間をおいてから思い出したのですが、【PayPal毎度ありがとうメール】も、その方のサーバーで動かなかったのです。調べてみると、PHPが誤動作していました。ここではとりあえず誤動作ということで書いてみます。他のサーバーではそんな誤動作は見たことがありません。ツールを動かすと必ず通る箇所なので、おかしければ他のユーザーさんの所でも、正常に動きません。ところが、他の方からはそのような連絡は全くないのです。PHPの設定の問題かなと思い調べたのですが、そのような事実は見つけられませんでした。誤動作しているのは、if(条件式){処理1return;}else{処理2return;}という構文です。条件式が真なのに、処理1が行われていなかったのです。この構文があると必ず誤動作するというわけではないのです。この時はif(条件式){処理1return;}処理2return;と書き換えることで、正常に動くようになりました。原因を突き止められないまま、WordPressの改変をお引き受けしたのですが、もしかすると何らかの関係があるのかもしれません。以前、別のサーバーでも、PHPがおかしかったことがありました。その時は【curl_setopt】関数でした。同じサーバー会社の別サーバー(おそらくハードが違う)では正常に動くのに、どうしても動かないアカウントがあったのです。サーバー管理会社に問い合わせたのですが、サーバー管理会社も原因がわからないとのことでした。このときは、サーバー(おそらくハードそのもの)を変えてもらったら、すんなり動きました。自分が契約しているサーバーではないので、とことん調べられませんが、何か不穏なものを感じてしまいます。コメントTop↑PHPコーディング変数の型と内容をファイルへ2013年03月17日PHPでコーディングしていて、変数の中身を確かめたい場合、【ver_dump】関数で変数の型と内容をブラウザへ表示することができます。ファイルへ書き出したい場合も多々あります。以前から何か方法があるはずだと思っていましたが、今回調べてみました。$result);fclose($handle);【$val】は配列でもOKです。Codaholicに詳しい説明があります。コメントTop↑PHPコーディングPHPでワーニングの非表示2013年01月22日PHPでエラー、ワーニング、ノーティスを出さない方法です。off】と加えればOKです。【php.ini】に【display_errors=off】あるいは【error_reporting=0】とすれば表示されなくなります。"Off");】あるいは【error_reporting(0);】を加えます。ソースへ記述すると、【php.ini】を値を上書きします。不特定多数に販売するツールには、ソースへ記述しておくのが便利です。ついでにテスト環境ではエラーやワーニングが表示され、配布時には非表示に、自動でなれば更に便利なんですが。ソースをテストとリリースで変更するのは、忘すれそうで怖いし、やりたくないです。滅多に変更しないクラスファイルへ記述、配布時に上書きしないようにする、テスト環境にのみダミーフィルを含め、ファイルがあるときのみエラーを表示する、なにか便利でミスの起こりにくい方法をさがさなければ。【error_reporting】は定義済み定数を使って、様々な設定が可能です。人力検索はてなシングスブログが参考になるかもしれません。"abc";func($callval);とします。関数の引数に【&】を付けると、参照引渡しというお約束です。呼び足し元の変数には【&】は付きません。知ってはいたのですが、ついうっかり呼び出し元の変数に【&】を付けてしまっていた箇所があったことがあります。関数をコピーして、呼び出し元へペースト、【&】を取り忘れていたのです。販売しているツールのソースは、かなり前に修正したのですが、本当に全て直っているか、新たに取り忘れていないか、少し心配になってきました。取り忘れていると、サーバーの設定によってはワーニングが出るのです。エラーと違いワーニングなので、動作には問題ありません。開発者には見えて、ユーザーには見えない設定が望ましいです。メジャーなサーバーではワーニングが出ない設定になっているので、問題はありません。今までは、ワーニングが出る場合、ユーザー様の【php.ini】に【allow_call_time_pass_reference=off】を付け加えて貰っていました。これをソースのほうから設定するように変更しようとと思い、【allow_call_time_pass_reference】につてい調べてみみました。すると、バージョン5.4.0で削除されていました。動いているバージョンは5.4.0より低いところも多々ありますが、バージョンアップされたときエラーが出るようになってしまう可能性もあるということです。使わないほうがいいでしょう。そもそも消し忘れ、付けるつもりがないのに付いているので、リリース前にチェックできるのが一番です。自分のサーバーで、今度は【allow_call_time_pass_reference=on】に設定し、チェックする方針にしました。親クラスを継承があるとします。子クラス2日時取得ファイル名に子クラス2と設定と実行したいとします。この場合、共通している日時取得は親クラスでやりたくなります。親クラスの【__construct】関数に日時処理を、それぞれの子クラスの【__construct】にファイル名の設定処理を書きました。ところが、関数が同じなので、親クラスの【__construct】は子クラスの【__construct】で上書きされてしまい、親クラスの【__construct】に書いた日時処理は実行されません。これをオーバーライドと言います。親クラスの【__construct】に書いた日時取得処理を実行するにはどうすればよいか。子クラスの【__construct】に【parent::__construct();】の処理を書けば実行されます。__constructparent::__construct();ファイル名に子クラス1と設定これで目的が達成されます。子クラスが2つくらいなら、子クラスの方へ書いてしまったほうが分かりやすいかもしれません。子の数が増えると親クラスで共通に処理しておかないと、メンテナンスが大変になります。PHPのオブジェクト指向入門にとても分かりやすい記事があります。コメントTop↑PHPコーディング配列キー重複チェック2013年01月06日PHPでコーディングしていて、配列キーが重複しているかどうか、調べたくなる状況に出くわしました。自分で書こうかなと思ったのですが、PHPは関数がたくさん用意されているので、ありそうな気がして調べてみました。たくあんありすぎて迷うことが多いですが。調べてみると案の定ありました。【array_count_values】関数です。array_count_values(重複を調べたい配列);でキーとその数が配列で返ってきます。2という配列が返ってきます。【PayPal毎度ありがとうメール】のユーザーさんから、一部のファイルがブラウザからアップロードできないとの連絡がありました。調べてみると、最後のファイルがアップロードできなくなっていました。以前はできていたので、途中からできなくなったということです。【$_FILES】を書き出してみました。最後のファイルだけ表示されません。認識していないということです。バージョンを上げたとき、機能を追加しました。機能追加に伴い、アップロードしなければならないファイルの数が増えました。これが原因ではないかと中りをつけます。/>でアップロードできるファイルの数が20までだということが分かりました。20を超えると無視されるそうです。これに違いありません。【max_file_uploads=30】(30には上限数を入れます。)と追記するだけです。多くの人が使うツールの場合、【php.ini】が使えないサーバーで使われることもありますから、他の対処法が必要です。不便ですが、1つのファイルをアップロードしたら次の入力欄が表示されるように変更しました。これで入力欄が20を超えなくなりました。ファイルアップロード数に上限があったんですね。今まで出あったことがありませんでした。各ツールでインストールURLに【www】があろうがなかろうが、動作するようにコーディングしているのですが、なぜか【www】があるとエラーになり、ないと動くという事例が出てきてしまいました。ユーザーさんの連絡でわかりました。ところが、こちらで再現しようとしても、再現しません。・・・?ソースを見ても、あってもなくても動くように書かれています。強制的に【www】を付けてテストをしても、ちゃんと動きます。何か勘違いしているか、サーバーが思ってもみない値を返してきているのでしょう。念には念を入れ、一部修正したので、しばらく様子見です。コメントTop↑PHPコーディング切り上げ、切り捨て、四捨五入2012年12月07日PHPで小数点以下切り捨てる処理が必要になったので、関数はないか調べてみました。切り捨て:ceil切り上げ:floor四捨五入:roundで実現できます。【round】関数は、丸める桁も指定できます。【ceil】、【floor】は桁の指定はできないようです。桁を指定したい場合は、10の何乗かを掛けて、関数を通し、その後掛けた数で割ればいいでしょう。【PayPalオートメール】では、cURL関数がインストールされていない場合にのみ、補助的に非SSL接続するように書いています。昨日cURL関数のことを調べているとき、非SSL接続でもエラーが起こっていることに気が付きました。今日はこのことを突っ込んで調べてみました。【PayPalオートメール】をリリースしたときは、非SSL接続も正常に動いていたので、おそらくその後PayPalの仕様が変わったのでしょう。302が返ってきていました。調べると、世界中で(?)困っている人がいたらしく、解決法が出てきました。PHPどうやら、SSL接続のみになったのではないかと思われます。PayPalのマニュアルでもSSLを強く推奨していますし、まぁそうでしょう。非SSL接続だと、PayPalが接続を拒否しています。全てのユーザーさんにサーバーでSSLを使えるようにして貰うのは酷なので、【PayPalオートメール】では、cURL関数を使っています。メジャーなサーバーにはインストールされていることは確認済みです。一応cURL関数がインストールされていない場合は、fsockopenでSSL接続するように書き換えました。【PayPalオートメール】のユーザーさんから、どうしても動かないとの連絡がありました。外からあれこれ調べてみたのですが、どうしても原因がわかりませんでした。結局そのユーザーさんのサーバーアカウントをお借りして調べることになりました。色々な情報を吐かせながら、どこが原因で動かないのか切り分けをしていくと、どうやら【PayPalオートメール】からPayPalへ接続するところで躓いていることがわかりました。【PayPalオートメール】はPHPのcURL関数を使って、PayPalにSSL接続をしています。【curl_setopt】関数がおかしい動きをしているようなのです。false);を走らせるとエラーで止まります。仕方ないのでコメントアウトして走らせてみました。他の色々なオプションを設定して、curl_exec($ch);を実行します。エラーが起こった場合、falseが返ってくるそうなのですが、何も返ってきません。curl_errno($ch);でエラー番号が、curl_error($ch);でエラーメッセージが取得できるので、出力させてみました。何じゃ?そのサーバーの別のアカウントで全く同じソースを走らせてみたのですが、何の問題もなく、あっけないほどあっさりと、走りました。以降、デフォルトでインストールされています。protocol・・・】というのもおかしいかな。protocol・・・】エラーが出るので、今のところどうにもならないか・・・まぁこれ以上は私には無理と判断したので、サーバーの管理者も巻き込んでもらうことにしました。ユーザーさんからも、他のサーバーにインストールしてみたら、すんなり動いたと連絡がありました。