- 投稿日:2019-07-27T22:53:00+09:00
php-master-changes 2019-07-26
今日は run-tests.php の修正、ドキュメントの修正があった!
2019-07-26
morrisonlevi: Remove .post files only for passing tests
- https://github.com/php/php-src/commit/5649267b257c78e46a934434c0bff894e0b5b694
- [7.2~]
- run-tests.php で、成功したテストのみ .post ファイルを削除するよう修正
- 残しときゃこけたテストの分をスクリプトで処理できるよということらしい
cmb69: Remove duplication
- https://github.com/php/php-src/commit/e1c80d8ea71c4ca70cf3fcd0dd8f4db1918bcd91
- [7.4~]
- UPGRADING で、zend.exception_ignore_args についての記述が二箇所にあったのを修正
theodorejb: Fix typos in UPGRADING and improve wording in a few places
- https://github.com/php/php-src/commit/0e6e2297fcb27103cc5d550ee8434680ff1e879e
- [7.4~]
- UPGRADING で、typo / 英語の修正
petk: Mention also API versions bumps
- https://github.com/php/php-src/commit/f1c4b48c840bc65782e77728feea9aa2e1268ca6
- [7.4~]
- docs/release-process.md で、API バージョン引き上げルールについて追記
- 投稿日:2019-07-27T17:34:49+09:00
PHP 配列・イテレータ ドキュメント
このページについて
配列やイテレータに関するインターフェースのドキュメントリンク集です。
PHP マニュアル > 関数リファレンス
https://www.php.net/manual/ja/funcref.phpPHP マニュアル > 関数リファレンス > その他の基本モジュール > JavaScript Object Notation
https://www.php.net/manual/ja/book.json.phpPHP マニュアル > 関数リファレンス > その他の基本モジュール > Standard PHP Library (SPL)
https://www.php.net/manual/ja/book.spl.phpPHP マニュアル > 言語リファレンス
https://www.php.net/manual/ja/langref.php配列
ArrayAccess インターフェイス
https://www.php.net/manual/ja/class.arrayaccess.php
配列としてオブジェクトにアクセスするための機能のインターフェイスです。
ArrayObject クラス
https://www.php.net/manual/ja/class.arrayobject.php
このクラスは、オブジェクトを配列として動作させます。
Countable インターフェイス
https://www.php.net/manual/ja/class.countable.php
Countable を実装したクラスは、 count() 関数で使用することができます。
ジェネレータ
https://www.php.net/manual/ja/language.generators.syntax.php
ジェネレータ関数の見た目はふつうの関数とほぼ同じです。違うのは、値を返すのではなく、 必要なだけ値を yield することです。
ジェネレータ関数が呼ばれると、反復処理が可能なオブジェクトを返します。 このオブジェクトを (foreach ループなどで) 反復させると、 値が必要になるたびに PHP がジェネレータ関数を呼びます。 そして、ジェネレータが値を yield した時点の状態を保存しておき、 次に値が必要になったときにはそこから再開できるようにします。
yield できる値がなくなると、ジェネレータ関数は何もせず単純に終了します。 呼び出し元のコードでは、配列の要素をすべて処理し終えた後のように、そのまま処理が続きます。
イテレータ
Iterator インターフェイス
https://www.php.net/manual/ja/class.iterator.php
外部のイテレータあるいはオブジェクト自身から反復処理を行うためのインターフェイスです。
IteratorAggregate インターフェイス
https://www.php.net/manual/ja/class.iteratoraggregate.php
外部イテレータを作成するためのインターフェイスです。
OuterIterator インターフェイス
https://www.php.net/manual/ja/class.outeriterator.php
OuterIterator を実装したクラスは、 イテレータ群の反復処理に使うことができます。
RecursiveIterator インターフェイス
https://www.php.net/manual/ja/class.recursiveiterator.php
RecursiveIterator を実装したクラスは、 イテレータ群を再帰的に反復処理するときに使うことができます。
SeekableIterator インターフェイス
https://www.php.net/manual/ja/class.seekableiterator.php
Seekable イテレータです。
SPL イテレータ
https://www.php.net/manual/ja/spl.iterators.php
SPL にはイテレータが用意されており、オブジェクトを反復処理することができます。
SPL イテレータクラスツリー
ArrayIterator RecursiveArrayIterator EmptyIterator IteratorIterator AppendIterator CachingIterator RecursiveCachingIterator FilterIterator CallbackFilterIterator RecursiveCallbackFilterIterator RecursiveFilterIterator ParentIterator RegexIterator RecursiveRegexIterator InfiniteIterator LimitIterator NoRewindIterator MultipleIterator RecursiveIteratorIterator RecursiveTreeIterator DirectoryIterator (extends SplFileInfo) FilesystemIterator GlobIterator RecursiveDirectoryIteratorデータ構造
https://www.php.net/manual/ja/spl.datastructures.php
SPL では、標準的なデータ構造を提供しています。 ここで、それらを実装ごとに分類してまとめます。
双方向リンクリスト
https://www.php.net/manual/ja/class.spldoublylinkedlist.php
双方向リンクリスト (Doubly Linked List: DLL) は、双方向のノードへのリンクを持つノードのリストです。 イテレータの操作、両隣へのアクセス、ノードの追加や削除のコストは、 データ構造が DLL の場合は O(1) となります。 これは、スタックやキューを実装するのに適しています。
SplDoublyLinkedList SplStack SplQueueヒープ
https://www.php.net/manual/ja/class.splheap.php
https://www.php.net/manual/ja/class.splpriorityqueue.phpヒープは、ツリー風の構造です。ヒープ特有の性質として、 個々のノードはその子ノードと等しいかそれより大きな値となります。 値の比較は、ヒープ全体の比較メソッドとして実装されているものを使用します。
SplHeap SplMaxHeap SplMinHeap SplPriorityQueue配列
https://www.php.net/manual/ja/class.splfixedarray.php
配列は、データを連続的に格納してインデックス経由でアクセスできるようにした構造です。 PHP の配列と混同しないようにしましょう。PHP の配列は、 実際のところは順序つきハッシュテーブルとして実装されています。
SplFixedArrayマップ
https://www.php.net/manual/ja/spl.datastructures.php
マップは、キー/値 のペアからなるデータ構造です。 PHP の配列は、整数値/文字列を値と対応させたマップとみなすことができます。 SPL では、オブジェクトとデータを対応させるマップを提供しています。 このマップは、オブジェクトの集合として扱うことができます。
SplObjectStorageObserver パターン
SplObserver インターフェイス
https://www.php.net/manual/ja/class.splobserver.php
SplObserver インターフェイスを SplSubject とともに使うと、Observer パターンを実装することができます。
SplSubject インターフェイス
https://www.php.net/manual/ja/class.splsubject.php
SplSubject インターフェイスを SplObserver とともに使うと、Observer パターンを実装することができます。
SPL 関数
https://www.php.net/manual/ja/ref.spl.php
iterator_apply
https://www.php.net/manual/ja/function.iterator-apply.php
ユーザー関数をイテレータのすべての要素でコールする
iterator_count
https://www.php.net/manual/ja/function.iterator-count.php
イテレータにある要素をカウントする
iterator_to_array
https://www.php.net/manual/ja/function.iterator-to-array.php
イテレータを配列にコピーする
データ保存関連
Serializable インターフェイス
https://www.php.net/manual/ja/class.serializable.php
独自のシリアライズ用のインターフェイスです。
このインターフェイスを実装したクラスは sleep() や __wakeup() をサポートしなくなります。 シリアライズが必要な場合には、自動的に serialize メソッドがコールされます。 このメソッドは __destruct() を実行しません。また、 メソッド内で明示的に書かない限りは一切の副作用を及ぼしません。 アンシリアライズされるときにはそのクラスが自動的に検知し、construct() メソッドのかわりに適切な unserialize() メソッドがコールされます。 標準のコンストラクタを実行させたい場合は、unserialize() メソッドの中でそれをコールします。
JsonSerializable インターフェイス
https://www.php.net/manual/ja/class.jsonserializable.php
JsonSerializable を実装したオブジェクトは、 json_encode() を呼んで処理されたときの自身の JSON 表現をカスタマイズできます。
あまり意識することのないクラス
Generator クラス
https://www.php.net/manual/ja/class.generator.php
Generator は ジェネレータ が返すオブジェクトです。
Closure クラス
https://www.php.net/manual/ja/class.closure.php
無名関数 を表すために使うクラスです。
- 投稿日:2019-07-27T17:34:49+09:00
PHP
このページについて
配列やイテレータに関するインターフェースのドキュメントリンク集です。
PHP マニュアル > 関数リファレンス
https://www.php.net/manual/ja/funcref.phpPHP マニュアル > 関数リファレンス > その他の基本モジュール > JavaScript Object Notation
https://www.php.net/manual/ja/book.json.phpPHP マニュアル > 関数リファレンス > その他の基本モジュール > Standard PHP Library (SPL)
https://www.php.net/manual/ja/book.spl.phpPHP マニュアル > 言語リファレンス
https://www.php.net/manual/ja/langref.php配列
ArrayAccess インターフェイス
https://www.php.net/manual/ja/class.arrayaccess.php
配列としてオブジェクトにアクセスするための機能のインターフェイスです。
ArrayObject クラス
https://www.php.net/manual/ja/class.arrayobject.php
このクラスは、オブジェクトを配列として動作させます。
Countable インターフェイス
https://www.php.net/manual/ja/class.countable.php
Countable を実装したクラスは、 count() 関数で使用することができます。
ジェネレータ
https://www.php.net/manual/ja/language.generators.syntax.php
ジェネレータ関数の見た目はふつうの関数とほぼ同じです。違うのは、値を返すのではなく、 必要なだけ値を yield することです。
ジェネレータ関数が呼ばれると、反復処理が可能なオブジェクトを返します。 このオブジェクトを (foreach ループなどで) 反復させると、 値が必要になるたびに PHP がジェネレータ関数を呼びます。 そして、ジェネレータが値を yield した時点の状態を保存しておき、 次に値が必要になったときにはそこから再開できるようにします。
yield できる値がなくなると、ジェネレータ関数は何もせず単純に終了します。 呼び出し元のコードでは、配列の要素をすべて処理し終えた後のように、そのまま処理が続きます。
イテレータ
Iterator インターフェイス
https://www.php.net/manual/ja/class.iterator.php
外部のイテレータあるいはオブジェクト自身から反復処理を行うためのインターフェイスです。
IteratorAggregate インターフェイス
https://www.php.net/manual/ja/class.iteratoraggregate.php
外部イテレータを作成するためのインターフェイスです。
OuterIterator インターフェイス
https://www.php.net/manual/ja/class.outeriterator.php
OuterIterator を実装したクラスは、 イテレータ群の反復処理に使うことができます。
RecursiveIterator インターフェイス
https://www.php.net/manual/ja/class.recursiveiterator.php
RecursiveIterator を実装したクラスは、 イテレータ群を再帰的に反復処理するときに使うことができます。
SeekableIterator インターフェイス
https://www.php.net/manual/ja/class.seekableiterator.php
Seekable イテレータです。
SPL イテレータ
https://www.php.net/manual/ja/spl.iterators.php
SPL にはイテレータが用意されており、オブジェクトを反復処理することができます。
SPL イテレータクラスツリー
ArrayIterator RecursiveArrayIterator EmptyIterator IteratorIterator AppendIterator CachingIterator RecursiveCachingIterator FilterIterator CallbackFilterIterator RecursiveCallbackFilterIterator RecursiveFilterIterator ParentIterator RegexIterator RecursiveRegexIterator InfiniteIterator LimitIterator NoRewindIterator MultipleIterator RecursiveIteratorIterator RecursiveTreeIterator DirectoryIterator (extends SplFileInfo) FilesystemIterator GlobIterator RecursiveDirectoryIteratorデータ構造
https://www.php.net/manual/ja/spl.datastructures.php
SPL では、標準的なデータ構造を提供しています。 ここで、それらを実装ごとに分類してまとめます。
双方向リンクリスト
https://www.php.net/manual/ja/class.spldoublylinkedlist.php
双方向リンクリスト (Doubly Linked List: DLL) は、双方向のノードへのリンクを持つノードのリストです。 イテレータの操作、両隣へのアクセス、ノードの追加や削除のコストは、 データ構造が DLL の場合は O(1) となります。 これは、スタックやキューを実装するのに適しています。
SplDoublyLinkedList SplStack SplQueueヒープ
https://www.php.net/manual/ja/class.splheap.php
https://www.php.net/manual/ja/class.splpriorityqueue.phpヒープは、ツリー風の構造です。ヒープ特有の性質として、 個々のノードはその子ノードと等しいかそれより大きな値となります。 値の比較は、ヒープ全体の比較メソッドとして実装されているものを使用します。
SplHeap SplMaxHeap SplMinHeap SplPriorityQueue配列
https://www.php.net/manual/ja/class.splfixedarray.php
配列は、データを連続的に格納してインデックス経由でアクセスできるようにした構造です。 PHP の配列と混同しないようにしましょう。PHP の配列は、 実際のところは順序つきハッシュテーブルとして実装されています。
SplFixedArrayマップ
https://www.php.net/manual/ja/spl.datastructures.php
マップは、キー/値 のペアからなるデータ構造です。 PHP の配列は、整数値/文字列を値と対応させたマップとみなすことができます。 SPL では、オブジェクトとデータを対応させるマップを提供しています。 このマップは、オブジェクトの集合として扱うことができます。
SplObjectStorageObserver パターン
SplObserver インターフェイス
https://www.php.net/manual/ja/class.splobserver.php
SplObserver インターフェイスを SplSubject とともに使うと、Observer パターンを実装することができます。
SplSubject インターフェイス
https://www.php.net/manual/ja/class.splsubject.php
SplSubject インターフェイスを SplObserver とともに使うと、Observer パターンを実装することができます。
SPL 関数
https://www.php.net/manual/ja/ref.spl.php
iterator_apply
https://www.php.net/manual/ja/function.iterator-apply.php
ユーザー関数をイテレータのすべての要素でコールする
iterator_count
https://www.php.net/manual/ja/function.iterator-count.php
イテレータにある要素をカウントする
iterator_to_array
https://www.php.net/manual/ja/function.iterator-to-array.php
イテレータを配列にコピーする
データ保存関連
Serializable インターフェイス
https://www.php.net/manual/ja/class.serializable.php
独自のシリアライズ用のインターフェイスです。
このインターフェイスを実装したクラスは sleep() や __wakeup() をサポートしなくなります。 シリアライズが必要な場合には、自動的に serialize メソッドがコールされます。 このメソッドは __destruct() を実行しません。また、 メソッド内で明示的に書かない限りは一切の副作用を及ぼしません。 アンシリアライズされるときにはそのクラスが自動的に検知し、construct() メソッドのかわりに適切な unserialize() メソッドがコールされます。 標準のコンストラクタを実行させたい場合は、unserialize() メソッドの中でそれをコールします。
JsonSerializable インターフェイス
https://www.php.net/manual/ja/class.jsonserializable.php
JsonSerializable を実装したオブジェクトは、 json_encode() を呼んで処理されたときの自身の JSON 表現をカスタマイズできます。
あまり意識することのないクラス
Generator クラス
https://www.php.net/manual/ja/class.generator.php
Generator は ジェネレータ が返すオブジェクトです。
Closure クラス
https://www.php.net/manual/ja/class.closure.php
無名関数 を表すために使うクラスです。
- 投稿日:2019-07-27T17:31:31+09:00
AWS Cloud9にSymfonyを構築する
テスト環境としてSymfonyが使える環境が欲しいと思い、Cloud9上に構築してみました。
今回構築したときの備忘録です。PHPのインストール
Cloud9のOSは、2019年7月時点でAmazon Linux2ではなく、以前のAmazon Linuxでした。
なので、amazon-linux-extras
は使えませんでした。$ cat /etc/system-release Amazon Linux AMI release 2018.03$ sudo yum -y update $ sudo yum -y install php72 php72-mbstring php72-pdo $ sudo unlink /usr/bin/php $ sudo ln -s /etc/alternatives/php7 /usr/bin/php $ php -v PHP 7.2.19 (cli) (built: Jun 12 2019 20:55:29) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologieshttps://qiita.com/kidatti/items/2d6a4a24f89dc71eb66e
Symfonyのインストール
$ wget https://get.symfony.com/cli/installer -O - | bash $ export PATH="$HOME/.symfony/bin:$PATH" >> .bash_profile $ sudo mv /home/ec2-user/.symfony/bin/symfony /usr/local/bin/symfony $ source .bash_profile $ symfony -v Symfony CLI version v4.6.2 (c) 2017-2019 Symfony SASComposerのインストール
$ php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" $ php -r "if (hash_file('sha384', 'composer-setup.php') === '48e3236262b34d30969dca3c37281b3b4bbe3221bda826ac6a9a62d6444cdb0dcd0615698a5cbe587c3f0fe57a54d8f5') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" $ php composer-setup.php $ php -r "unlink('composer-setup.php');" $ sudo mv composer.phar /usr/local/bin/composer $ composer -v ______ / ____/___ ____ ___ ____ ____ ________ _____ / / / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/ / /___/ /_/ / / / / / / /_/ / /_/ (__ ) __/ / \____/\____/_/ /_/ /_/ .___/\____/____/\___/_/ /_/ Composer version 1.8.6 2019-06-11 15:03:05https://getcomposer.org/download/
http://symdoc.kwalk.jp/doc/book/installationSymfonyの起動
Cloud9では外部からアクセスできるポート番号が決まっているため、ポート番号を指定して起動する必要があります。
$ symfony new --full my_project $ cd my_project/ $ php bin/console server:start *:8080メニュー > Preview > Preview Running Applicationを押すと実行ページのプレビューが表示されます。
Symfonyの停止
$ php bin/console server:stop
(補足)アプリの状態をするコマンド
$ php bin/console about
- 投稿日:2019-07-27T17:22:25+09:00
PHPのdate関数にいろんなものを突っ込んでみた
PHPのdate関数にいろんなものを突っ込んだ時のテスト
日付が1日足りない場合の時の挙動なんかおもしろいかも。echo $birth . ':' . date('Y/m/d H:i:s', strtotime($birth)); //:1970/01/01 09:00:00日付形式に変換できないものは「1970/01/01 09:00:00」になるみたいです。
$birth = null; echo $birth . ':' . date('Y/m/d', strtotime($birth)); //:1970/01/01 $birth = ''; echo $birth . ':' . date('Y/m/d', strtotime($birth)); //:1970/01/01 $birth = 'あああ'; echo $birth . ':' . date('Y/m/d', strtotime($birth)); //1999/99/99:1970/01/01 $birth = '1999/99/99'; echo $birth . ':' . date('Y/m/d', strtotime($birth)); //1999/99/99:1970/01/01 $birth = '1999/00/00'; echo $birth . ':' . date('Y/m/d', strtotime($birth)); //1999/00/00:1998/11/30 $birth = '0000/00/00'; echo $birth . ':' . date('Y/m/d', strtotime($birth)); //0000/00/00:-0001/11/30 $birth = '1999/01/01'; echo $birth . ':' . date('Y/m/d', strtotime($birth)); //1999/01/01:1999/01/01 [/php] 「0000」の場合は日付がずれるみたいです。
- 投稿日:2019-07-27T17:20:02+09:00
PHPのcurlでLocationを辿ろうとしたらエラー
curlのリダイレクトに対応するために、curl_setoptで
CURLOPT_FOLLOWLOCATIONを設定しようとしたらこんなエラーがでました。CURLOPT_FOLLOWLOCATION cannot be activated when safe_mode is enabled or an open_basedir is set in /home/***/***/test.php on line 123原因はPHPが動いているレンタルサーバーがセーフモードで実行していたためでした。
curlでLocationをたどるために以下の方法を使いました。$ch = curl_init(); $limit = 5; $url = "http://example.com/has/some/redirect"; do { curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $url = curl_getinfo($ch, CURLINFO_REDIRECT_URL); } while ($code === 301 || $code === 302 and $limit--); ``
- 投稿日:2019-07-27T17:17:28+09:00
PHPで画像添付メール送信
メールを送信する前に画像のサイズ、形式のチェックをします。
input.php
<?php header('Content-type: text/html; charset=UTF-8'); //メッセージ取得初期化 $MESSAGE = isset($_COOKIE['MESSAGE']) ? $_COOKIE['MESSAGE'] : NULL; setcookie('MESSAGE', '', time() + 3600, '/'); ?> <?=nl2br($MESSAGE);?> <form method="POST" action="upload.php" enctype="multipart/form-data"> <input type="file" name="upimg" accept="image/*"> <input type="submit"> </form>upload.php
<?php header('Content-type: text/html; charset=UTF-8'); try { $ERRMSG = NULL; //――――――――――――――――――――――――――――――――――― //送信画像チェック //――――――――――――――――――――――――――――――――――― $IMGNAME = isset($_FILES['upimg']['name']) ? $_FILES['upimg']['name'] : NULL; $IMGTMP = isset($_FILES['upimg']['tmp_name']) ? $_FILES['upimg']['tmp_name'] : NULL; $IMGUPERR = isset($_FILES['upimg']['error']) ? $_FILES['upimg']['error'] : NULL; $fp = @fopen($IMGTMP, "rb"); $img = @fread($fp, filesize($IMGTMP)); @fclose($fp); $IMGSIZE = floor(strlen($img) / 1024); $ENCODEIMG = base64_encode($img); $imginfo = @getimagesize('data:application/octet-stream;base64,' . $ENCODEIMG); $IMGTYPE = $imginfo['mime']; $INPERRFLG = 0; $INPERRMSG = NULL; if($IMGUPERR == UPLOAD_ERR_NO_FILE){ $INPERRFLG = 1; $INPERRMSG .= 'ファイルを選択してください' . "\n"; }else if($IMGUPERR == UPLOAD_ERR_PARTIAL){ $INPERRFLG = 1; $INPERRMSG .= 'ファイルのアップに失敗しました。' . "\n"; }else if($IMGUPERR == UPLOAD_ERR_INI_SIZE || $IMGUPERR == UPLOAD_ERR_FORM_SIZE){ $INPERRFLG = 1; $INPERRMSG .= 'ファイルサイズが大きすぎます' . "\n"; }else{ if($IMGTYPE == 'image/gif' || $IMGTYPE == 'image/jpeg' || $IMGTYPE == 'image/png'){ }else{ $INPERRFLG = 1; $INPERRMSG .= '画像を選択してください。' . "\n"; } if(!preg_match('/^.*\.(jpg|jpeg|gif|png)$/i', $IMGNAME)){ $INPERRFLG = 1; $INPERRMSG .= 'jpg、gif、pngの拡張子を選択してください。' . "\n"; } if($IMGSIZE > 1024){ $INPERRFLG = 1; $INPERRMSG .= 'サイズを1MB以下にしてください。' . "\n"; } } if($INPERRFLG == 1){ setcookie('MESSAGE', $INPERRMSG, time() + 3600, '/'); header('Location: http://' . $_SERVER['SERVER_NAME'] . '/input.php'); exit; } //――――――――――――――――――――――――――――――――――― //メール送信 //――――――――――――――――――――――――――――――――――― $BOUNDARY = '__BOUNDARY__' .md5(rand()); $to = 'webmaster@example.com'; $subject = '件名'; $header = implode("\r\n",array( 'Content-Type: multipart/mixed;boundary=' . $BOUNDARY , 'From: webmaster@example.com', 'Reply-To: webmaster@example.com', )); $body = "--" . $BOUNDARY . "\n"; $body .= 'Content-Type: text/plain; charset="ISO-2022-JP' . "\n"; $body .= '画像が送信されました。' . "\n"; $body .= '--' . $BOUNDARY . "\n"; $body .= 'Content-Type: ' . $IMGTYPE . '; name=' . $IMGNAME . "\n"; $body .= 'Content-Disposition: attachment; filename=' . $IMGNAME . "\n"; $body .= 'Content-Transfer-Encoding: base64' . "\n"; $body .= chunk_split($ENCODEIMG) . "\n"; $body .= '--' . $BOUNDARY . '--'; mail($to, $subject, $body, $header); } catch (Exception $e) { $ERRMSG = $e->getMessage(); } ?> <?php if(mb_strlen($ERRMSG) > 0) : ?> <p><?=$ERRMSG;?></p> <?php else : ?> <p>メールを送信しました。</p> <?php endif; ?>ほぼこちらのサイトを参考にさせて頂きました。
参考サイト
- PHP: HTTP コンテキストオプション - Manual
- 投稿日:2019-07-27T17:12:55+09:00
PHPでRSSを作成
rdf拡張子のRSSを表示させる場合は以下の行が書かれた「.htaccess」を作成して、表示させたいrdfのディレクトリに置いてください。
「.htaccess」を作成させる場合はサーバーにアップしてからリネームすると「.」がついたファイルを作成できます。.htaccess
AddType application/xml .rdfSimpleXMLElementを使う事で、簡単にRSSを作成できます。
今回は作成したRSSをすぐに表示させていますが、一度ファイルとして保存したものを表示する方法でもいいと思います。
表示されない場合はhtmlspecialchars()で文字をエスケープしてから表示してみてください。
myblog.rdfを保存する場合は、サーバーの公開ディレクトリ直下にrssフォルダを作成してください。rss.php
<?php try{ $RSS = <<<EOT <?xml version="1.0" encoding="UTF-8"?> <rss version="2.0"> <channel> <language>ja</language> </channel> </rss> EOT; $rssFileName = 'myblog.rdf'; $XML = new SimpleXMLElement($RSS); $XML->channel->addChild('title', "ブログタイトル!"); $XML->channel->addChild('link', 'http://' . $_SERVER['HTTP_HOST'] . '/rss/' . $rssFileName); $XML->channel->addChild('description', "ブログの更新情報です"); $item = $XML->channel->addChild('item'); $item->addChild('title', "記事タイトル"); $item->addChild('link', 'http://' . $_SERVER['HTTP_HOST'] . "/page/mypage.html"); $item->addChild('category', "カテゴリ"); $item->addChild('description', "記事についての説明"); $item->addChild('content', "記事の中身"); $item->addChild('date', date('Y-m-d H:i:s')); header('Content-Type: text/xml'); ob_end_clean(); echo $XML->asXML(); $file = fopen($_SERVER['DOCUMENT_ROOT'] . '/rss/' . $rssFileName, "w"); fwrite($file, $XML->asXML()); fclose($file); }catch ( Exception $e ) { // var_dump($e->getMessage()); } ?>ポイントとしてはob_end_cleanを使用することで、作成したRSSを直接表示させることが出来ます。
- 投稿日:2019-07-27T16:47:18+09:00
Node.jsでCSVからPHPに雑に変換してみる
WordPressのリプレイスもどき案件で大量(1,000件以上)のリダイレクトをすることになりそうなので、後の自分のダメージを減らすべく、準備がてらなるべく楽にリダイレクト出来る方法を考えました。
表題の通り 雑に 書いています。取り敢えず目的を果たす為だけにつくりました。達成したいこと
- 大量のリダイレクトの処理の手間を減らしたい。
目視で1件ずつは勘弁…- 本番・開発・ローカルでファイルを共有出来る状態にしておきたい。
- サーバーの仕様に影響される
.htaccess
は本番・開発・ローカルで共有したくない。(共有出来ない可能性がある。)- 自分以外の人もリダイレクト元とリダイレクト先の情報が一度に確認出来る状態にしておきたい。
- プラグインを利用した場合、管理画面から1件ずつ確認するのが面倒臭そう。間違いに気付きにくい。
- GoogleDriveなどで表にしておいて、必要な情報のみ抜き出して編集・閲覧出来る状態にしておけば、間違いに気付きやすくなる。
考えた方法
リダイレクト元とリダイレクト先のURLを記載したCSVファイルを作り、リダイレクト用のPHPに変換し、
header('Location:...')
を利用してリダイレクト。
今回はリダイレクトの条件の部分の変換を行いました。(header('Location...
を書いてある別ファイルにincludeする前提)プラグインを使用しなかった理由
- プラグインによっては更新が止まっているものがある(アップデート後に不具合を起こす可能性がある)。
- リダイレクトの設定が
.htaccess
に吐き出されるプラグインは避けたい。
- 本番・開発・ローカルで
.htaccess
を使い回すことは避けたい。前提条件
Node.js
をインストール済みであること使うもの
準備
パッケージをインストール
yarn add csv -D若しくは
npm i csv -Dcsvファイルと変換先の空のファイルを用意
csv
title
:ページのタイトルold
:リダイレクト元のドメインより後のURLnew
:リダイレクト先のドメインより後のURLCSVのデータtitle,old,new Contact,contact,sample-page りだいれくとのてすと。さんぷるページに移動,19,sample-page りだいれくとてすと2。プライバシーポリシーにいどう,21,privacy-policy空のファイル
中身は書かずに
hoge.php
で保存スクリプトを書く
convert-csv.js
で保存変換用スクリプト/** * csvからリダイレクト用のPHPに変換するスクリプト */ const fs = require('fs'); const csv = require('csv'); /** * データをパースする */ const parser = csv.parse( { columns: true }, ( error, data ) => { if ( error ) { console.error(error); return; } /** * データからリダイレクト元とリダイレクト先のURLのみ取り出した配列を作成 */ const redirectUrlArray = data.map((obj) => { const oldUrl = obj['old']; const newUrl = obj['new']; return { oldUrl, newUrl }; }); /** * リダイレクト元とリダイレクト先の配列を元にPHPのswitch文の中身を作成 */ const arrayText = redirectUrlArray.map((obj) => { return ` case home_url('/').'${obj['oldUrl']}/':\n $redirectUrl = home_url('/').'${obj['newUrl']}/';\n break;\n`; }); /** * テキストに変換 */ const outText = arrayText.join(',').replace(/,/g, ''); /** * PHPファイルの中身 */ const outputData = `<?php\n switch ($url) {\n${outText}\n }\n?>`; /** * ファイルに書き出し */ fs.writeFile(__dirname + 'hoge.phpのファイルパス', outputData, (error) => { if ( error ) { console.error(error); return; } console.log(outputData); console.log('変換完了'); }); }); /** * ファイルの読み込み */ fs.createReadStream(__dirname + 'CSVデータのファイルパス').pipe(parser);実行
convert-csv.js
を保存したディレクトリで以下を実行node convert-csv.js実行結果
<?php switch ($url) { case home_url('/').'contact/': $redirectUrl = home_url('/').'sample-page/'; break; case home_url('/').'19/': $redirectUrl = home_url('/').'sample-page/'; break; case home_url('/').'21/': $redirectUrl = home_url('/').'privacy-policy/'; break; } ?>最後の
break;
の後に改行が入りますが動作に影響は無いので無視で・・・
- 投稿日:2019-07-27T16:33:53+09:00
我流VRMMOゲーム制作法(要点まとめ)
VRMMOゲームが作りたい!
私はVRMMOゲームを制作しています。
現在は仕様を練っている所です。今回の記事が、私と同様VRMMOゲームを作ろうとする人の役に立つ事を願います。
制作環境
まず、ゲーム制作環境ですが、Unityにて開発、steamへアップロードを想定しています。
これは、OpenVR SDKやsteamVR pluginを初めとした外部技術導入の容易さからです。以下に私の使用する外部技術を挙げます。
OpenVR SDK:UnityゲームをVR対応にする為に用います。情報が少ないです。
steamVR Plugin:ゲームをVR対応にする為に用います。こちらはカメラや各種コントローラ入力を扱います。
steamworks SDK,API:課金やアップロードなどを扱います。クライアント・自分のサーバ・steam WEB APIサーバでやり取りします。
随時記事を更新作成します。
ログイン
次に、ログイン機能についてです。
ログインにおいてはクライアント、サーバ間のやり取りが必要となります。
参考までに、クライアントから、IDとパスワード、アバター情報をサーバに送信します。
VRM-FBX-JSONは相互変換可能です。アバター情報をJSON形式化します。
クライアント:Unity及びPHPを用いてテキストデータ及びJSON形式データをHTTPにて送信
サーバ:nginxにてテキストデータを取得、PHPを介してテキストデータをMySQLへ格納
2.1 PHPにてアバターデータを取得、PHPを介してJSON形式データをMySQLへ格納3.サーバ内でデータを照合します。ハッシュ化された値が正しいか確認。暗号化はダメです。復号されてしまうので。
4.データが正しい場合、PHPを介してサーバからクライアントへ照合完了を伝え、ログイン完了となります。
情報照合方法は改めて検討します。
また、細かな手続きについては都度記事を更新作成します。
アバター生成
JsonUtilityを用いて、MySQLから取り出したJSONをアバターに復元します。
90fpsの維持
1.クライアントは、Unity,C++を用いて、常時アバターの位置情報とアクション内容情報をJSON形式でUDPにてサーバに送信します。
同時に、サーバから情報を受け取った場合、空間情報を全て更新します。
2.サーバは、クライアントから受け取ったJSON情報を元に、各々、位置、アクション情報を更新します。
その後、更新したJSON情報をサーバ間で同期します。
最後に、同期された情報をクライアントへUDPにてJSON情報を送信します。
3.クライアントは受け取ったJSONデータを元に空間を再構成します。
これを1秒間に180回行います。UDP通信なので半分の通信は失敗する想定です。
細かな手続きは随時記事を作成更新します。
実験してみないと分からない事が多いです。
最後に
VRMMOゲームのシステムについて考えてみました。
一緒に作りたいという方は連絡下さい。作りましょう。
ご意見のある方がいらっしゃいましたら、アドバイスを下さい。
分からない事が多い為、情報提供頂けると助かります。
よろしくお願いします。
- 投稿日:2019-07-27T16:33:53+09:00
我流VRMMOゲーム制作法(要点)
VRMMOゲームが作りたい!
私はVRMMOゲームを制作しています。
現在は仕様を練っている所です。今回の記事が、私と同様VRMMOゲームを作ろうとする人の役に立つ事を願います。
制作環境
まず、ゲーム制作環境ですが、Unityにて開発、steamへアップロードを想定しています。
これは、OpenVR SDKやsteamVR pluginを初めとした外部技術導入の容易さからです。以下に私の使用する外部技術を挙げます。
OpenVR SDK:UnityゲームをVR対応にする為に用います。情報が少ないです。
steamVR Plugin:ゲームをVR対応にする為に用います。こちらはカメラや各種コントローラ入力を扱います。
steamworks SDK,API:課金やアップロードなどを扱います。クライアント・自分のサーバ・steam WEB APIサーバでやり取りします。
随時記事を更新作成します。
ログイン
次に、ログイン機能についてです。
ログインにおいてはクライアント、サーバ間のやり取りが必要となります。
参考までに、クライアントから、IDとパスワード、アバター情報をサーバに送信します。
VRM-FBX-JSONは相互変換可能です。アバター情報をJSON形式化します。
クライアント:Unity及びPHPを用いてテキストデータ及びJSON形式データをHTTPにて送信
サーバ:nginxにてテキストデータを取得、PHPを介してテキストデータをMySQLへ格納
2.1 PHPにてアバターデータを取得、PHPを介してJSON形式データをMySQLへ格納3.サーバ内でデータを照合します。ハッシュ化された値が正しいか確認。暗号化はダメです。復号されてしまうので。
4.データが正しい場合、PHPを介してサーバからクライアントへ照合完了を伝え、ログイン完了となります。
情報照合方法は改めて検討します。
また、細かな手続きについては都度記事を更新作成します。
アバター生成
JsonUtilityを用いて、MySQLから取り出したJSONをアバターに復元します。
90fpsの維持
1.クライアントは、Unity,C++を用いて、常時アバターの位置情報とアクション内容情報をJSON形式でUDPにてサーバに送信します。
同時に、サーバから情報を受け取った場合、空間情報を全て更新します。
2.サーバは、クライアントから受け取ったJSON情報を元に、各々、位置、アクション情報を更新します。
その後、更新したJSON情報をサーバ間で同期します。
最後に、同期された情報をクライアントへUDPにてJSON情報を送信します。
3.クライアントは受け取ったJSONデータを元に空間を再構成します。
これを1秒間に180回行います。UDP通信なので半分の通信は失敗する想定です。
細かな手続きは随時記事を作成更新します。
実験してみないと分からない事が多いです。
最後に
VRMMOゲームのシステムについて考えてみました。
一緒に作りたいという方は連絡下さい。作りましょう。
ご意見のある方がいらっしゃいましたら、アドバイスを下さい。
分からない事が多い為、情報提供頂けると助かります。
よろしくお願いします。
- 投稿日:2019-07-27T16:04:57+09:00
Laravel ide-helperでモデルのIDE保管用コメントを作成する
LaravelでIDE補完されやすくするではide-helperの導入とLaravelの基本クラスのIDE保管用ファイルの作成方法を紹介しました。
今回はide-helperを使用してEloquentクラスを継承したモデルのプロパティなどをテーブルから作成してくれる機能を紹介します。
使用するテーブルとモデルはLaravelでマイグレーションしてモデルファイルを作成するの記事でご紹介したshopsテーブル/Shopモデルを使用します。
doctrine/dbalのインストール
ide-helperでモデルにコメントを入れる機能を使用するにはdoctrine/dbalの追加が必要になるので下記コマンドでインストールします。
composer require --dev doctrine/dbal
コマンドの実行
インストールしたら下記コマンドを実行すると書くモデルファイルに対してIDE補完用のコメントが追加されます。
php artisan ide-helper:modelsコマンドを実行すると上書きしていいか聞かれるので、yesと入力してenterを押下します。
するとこのような何の記述もないモデルファイルが
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Shop extends Model { // }このようになります。
<?php namespace App; use Illuminate\Database\Eloquent\Model; /** * App\Shop * * @property int $id * @property string|null $name 店舗名 * @property string|null $sub_name 支店名 * @property \Illuminate\Support\Carbon|null $created_at * @property \Illuminate\Support\Carbon|null $updated_at * @method static \Illuminate\Database\Eloquent\Builder|\App\Shop newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|\App\Shop newQuery() * @method static \Illuminate\Database\Eloquent\Builder|\App\Shop query() * @method static \Illuminate\Database\Eloquent\Builder|\App\Shop whereCreatedAt($value) * @method static \Illuminate\Database\Eloquent\Builder|\App\Shop whereId($value) * @method static \Illuminate\Database\Eloquent\Builder|\App\Shop whereName($value) * @method static \Illuminate\Database\Eloquent\Builder|\App\Shop whereSubName($value) * @method static \Illuminate\Database\Eloquent\Builder|\App\Shop whereUpdatedAt($value) * @mixin \Eloquent */ class Shop extends Model { // }もしプロジェクトルート/app配下以外にモデルファイルを作成している場合(例えばapp/Models/Shop.phpみたいな場合は)
php artisan ide-helper:models App\\Models\\Shopのようにnamespaceを指定してあげると反映されます。
- 投稿日:2019-07-27T14:42:46+09:00
PHPでデータベース接続(PDO)
PHPでデータベース接続する時、PDO周りは不明な用語が沢山出てきて混乱しがちな為、
単語や情報を一つずつ整理してロジックを組み立てる必要がある。データベース接続の流れ
データベースの接続 → データベースの操作 → データベースとの接続終了
という流れが基本的な鉄則。例えるなら、
本棚から必要な本を見つけ手に取る(接続)
本の中から必要な情報を探す(操作)
本を閉じ、本棚にしまう(接続終了)
と行った所。書き方 判例
接続方法自体は色々あるが現在は、PDO(PHP Data Object)が主流。
下記判例を示すと、
php<?php //まず登録項目3点を変数化する。 $dsn = 'mysql:dbname=指定のテーブル;host=指定のホスト名;charset=utf8'; $user ='RDBMS登録のユーザー名(rootとか)'; $password ='RDBMS登録のユーザーパスワード(rootとか)'; //例外処理 try{ $dbh = new PDO($dsn, $user, $password); //ここが接続の文 $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $sql = "SELECT * FROM recipes"; $stmt = $dbh->query($sql); $result = $stmt->fetchAll(PDO::FETCH_ASSOC); echo $result; $dbh = null; }catch(Exception $e){ echo"接続失敗:". htmlspecialchars($e->getMessage(),ENT_QUOTES, 'UTF-8') . "<br>"; die(); } ?>こんな所でしょうか?
初心者がいきなりこれを見ても、は?って感じになりますよね。
いろんな部分が、は?って感じですよね。
何回写経した所で、一つ一つの箇所が理解出来ない事には、このPDO周りの部分は毎回大きく時間が取られてしまいます。そこで一つ一つパーツごとに切り分けて、ロジックを噛み砕いていかなくてはいけません。
・new PDO・・・PDOで接続。newはそのまま「新たに」って意味で、ここはもうそういう書き方をしないといけないと思うようにしましょう。
new PDOの後に、接続情報やユーザー名、パスワードなどを指定して準備していく。
ここまでの固まりを「$dbh」という変数に格納する。
今後データベースの機能を使う場合には、この変数「$dbh」を指定する。・$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
・・・生成したPDOオブジェクトに対して、setAttribute()メソッドで設定を行い、
データベース接続の設定(エラーモードの設定)をこの行でやっている。
setAttribute()メソッドは、データベース接続時の設定や、SQL文実行時の挙動など、
データベースハンドルの属性を変更するためのメソッド。$stmt = $dbh->query($sql);
・・・①$dbhはデータベースの接続を設定した変数
②queryは問い合わせ、質問するといったイメージ
③$sqlはSQL文の内容
という流れから、この文は、SQL文を実行して結果を問い合わせるという意味が入っている。
->query()とする事で、PDOの機能の問い合わせを実行する事が出来た。$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
・・・SQL文の実行結果をカラム名をつけた配列として取り出す。
配列として全て取り出す命令はfetchAll()という関数。
PDO::FETCH_ASSOCは、実行結果をつけた配列として返す。
・$e->getMessage()
・・・catch時にExceptionを代入する変数$eを用意する。Exceptionは例外という意味。
$eの中にあるメッセージを取得する命令getMessage()は、$dbhで指定した時と同様に、
->(アロー演算子)で指定する。
$e->getMessage()とすれば、エラー発生時のメッセージを取得できる。こうやって一つ一つ要約していくと、順序立てて処理が進んでいる事が分かる。
まずデータベース接続する。
エラー設定をする。
SQL文を発行する準備をする。
SQL文を発行して問い合わせる。
SQL文の実行結果を取り出す。
データベース接続を切断する。といった流れとして、翻訳が成り立つ。
PDOstatementの所はもう少し詳細が欲しい所なので、それはまた次の機会にまとめる。
- 投稿日:2019-07-27T12:31:07+09:00
YouTubeのチャンネルを分析するサービスで利用したYouTube Data APIについて
新たにYouTubeのチャンネルを分析してチャンネルの登録者数、総再生回数を取得して表示する他、動画の再生数の多い順に表示するWebサービスを作ったので、その中で利用したYouTube Data APIの関数について解説します。
作ったサービスはこちらになります。
Bestube -ベスチューブ-
https://www.bestube.net/
YouTubeのAPIは複数用意されていて、訪問者が視聴した時間、視聴者の離脱率など主に自分の管理している動画に関する情報を取得するAPIであるYouTube Analytics API、YouTube Reporting APIと、認証なしでYouTube上の動画やチャンネルの情報を取得できるYouTube Data APIがあります。
BestubeではYouTube Data APIを利用してチャンネル情報や動画情報を取得しています。
具体的には、まず、Google Developer Consoleでアカウント登録をしてプロジェクトを作成します。
その上でプロジェクトのYouTube Data APIを有効化し、認証キーを作成します。
認証キーを取得したら、Google API LibrariesをGitHubから取得してインストールします。
言語はそれぞれ適切なものを利用するものとしますが、BestubeはPHPで書かれていますので、こちら(https://github.com/googleapis/google-api-php-client?hl=ja) からダウンロードしました。Bestubeではチャンネル情報を取得する時に以下の処理をしています。
1.チャンネルのIDからチャンネルの情報(紹介文、サムネイル、総再生回数など)を取得する。→Channelsのlistメソッドを呼ぶ(https://developers.google.com/youtube/v3/getting-started) 。
2.チャンネルに登録されている動画を検索し、チャンネルに投稿されている動画のIDを全て取得する。→Searchのlistメソッドを呼ぶ(https://developers.google.com/youtube/v3/guides/implementation/search) 。
3.取得した動画のID(複数を同時に取得可)から動画の情報(統計情報やサムネイルなど)を取得する。 →Videosのlistメソッドで取得(https://developers.google.com/youtube/v3/guides/implementation/videos) 。
この三つの過程によってYouTubeチャンネルの動画人気ランキングを作成します。一度にこれらの情報を取得できれば楽なのですが、チャンネルの情報に加えてチャンネルに投稿された動画の詳細情報についても掲載する必要があるので自分の知る限りですとこれらの処理が必要になってくると思われます。
YouTube APIは定められたクォータ(利用可能なAPIのコール制限)内でしか使用できないきまりになっています。このチャンネル情報の取得では必要となるクォータの量がかなり多いので、それをどうにか圧縮することが今後の課題です。
改善点が見つかったらまた追加いたします。