ITかあさんの楽しいPHP入門 ITかあさん

ITかあさん

目次:ITかあさんの楽しいPHP入門

PHPの入門書なんて難しかったり、物足りなかったり、サンプルスクリプトが実用的でなかったり。
楽しくて今すぐ使いたくなるPHPのスクリプトを紹介&解説。
主催しているLinuxお勉強しよう会で紹介したPHPネタもこちらで解説していきます。

初心者も分かるようPHPメールフォームを解説

初心者も分かるようPHPメールフォームを解説

PHPの登竜門!PHPメールフォームを今更ですが 解説してみたいと思います。

完成品はこちら

ダウンロードはこちら

メールフォームは簡単ではない!

大抵一番最初に作るPHPのプログラムチックなモノと言えばメールフォームですが、はっきり言ってめちゃめちゃ難しいです。

PHP●年やっている私も、たまに頭を抱えるメールフォームの事例もありますから決して侮ってはいけません。

メールフォームは文字化けと、迷惑メールに振り分けられないようにする

この2つの戦いですが、これが難しいです。

ですから、今回なら$_Postと$_Sessioこの2つの使い方が分かればよいと思います。
後はコピペで メールフォームの項目を自分で増やせたら それでOKなのです。

使う関数

色々ありますが、今回のケースならsession_start()と、mb_send_mail()の2つを覚えて、残りの文字コードに関する設定のあたりは決まり文句のように
コピペして 『テクマクマヤコン・テクマクマヤコン』と覚えて下さい。

session_start()…Sessionをスタートさせる関数
mb_send_mail()…メール送信を実行する関数
mb_internal_encoding()…文字コード指定する関数
mb_language()…カレントの言語を日本語に設定する関数
if文・・・構文。●●だったら▲▲▲してね!

関数が少なすぎませんか?

『オレが読んだ参考書には htmlspecialcharsとかメールアドレスの正規表現チェックとか色々あったぞ!手抜きすんな!』

と、ツッコミ入れてくる坊やがいると思いますが、ナンセンス!
極力面倒な処理はjQueryのフォームのバリデータを使ったほうがリアルタイムで入力チェックしてくれますし、
最低限悪さが出来ないような処理だけ入れてあげればいいんです。

入門なので、極力使う関数は少なめにして、すぐにメール送信が実行できるようにしましょう。

誰でもスクレイピング!DOM要素を引っこ抜くSimple HTML Dom

誰でもスクレイピング!DOM要素を引っこ抜くSimple HTML Dom

Linuxエンジニアの方と一緒に主催している勉強会で『スクレイピング』についてリクエストを頂いたことがきっかけで『WEBサイト上で表示されているテキストやリンクなどのDOM要素をスクレイピングで簡単に引っこ抜いてしまおう!』ということになりました。
人生初のスクレイピング体験となりましたが非常に簡単!ではいってみよ~

1分で分かるスクレイピング

そもそもスクレイピングとは

・ウェブサイトのデータを必要な部分だけ抽出して利用すること

DOM要素として必要な部分だけを抽出して、ほとんどの場合自分のデータベースに登録して実際には運用したりします。

スクレイピング注意点

・著作権問題

WEBサイトは著作権で守られています。許可無く勝手に人様のサイトから情報だけ抜き出して自分のサイト上に公開することは出来ません。この著作権の問題には十分注意してください。

スクレイピング便利クラス Simple HTML Dom

スクレイピングの方法はいくつか存在するのがですが、私はSimple HTML Domを好んで使っています。色々調べた結果、個人的にはこれが一番使い易いと思いました。
サイトからダウンロードし、simplehtmldom_1_5フォルダをスクレイピングを実行したいサーバーにアップして、simple_html_dom.phpを呼び出すだけで準備は完了します。

引っこ抜きの指定が実はCSSそっくり!だからWEBデザイナーにも!

簡単ですが、データの引っこ抜き方です。『ここを引っこ抜きたい!』という部分を指定します。

下記の赤字部分に注目。引っこ抜きたい(スクレイピングしたい)DOMの指定。

$html = file_get_html( ‘http://から始まるURLで指定’ );//何のURLからスクレイピングするか
foreach($html->find(‘a’) as $element)

id=”contents”の中のulを引っ張りたいなら

foreach( $html->find( ‘#content ul’ ) as $ul )

DOMの指定が#contentで、#を使えて入れ子にするあたりが全くCSSの指定と一緒なのでWEBデザイナーにも優しい設計です!

1分でスクレイピング実行!

ITかあさんのブログ内をスクレイピング実行して、どのように抜き出せるのか実際にやってみましょう。

例えば、ITかあさんのブログのトップページ中のリンク(hrefの中身)を引っ張るとしたらこうなります。

// simple_html_dom.phpファイルの読み込み
include_once('simplehtmldom_1_5/simple_html_dom.php');
//スクレイピングしたいURLを指定
$html = file_get_html( 'http://www.kaasan.info/' );
//リンク
foreach($html->find('a') as $element)
echo $element->href . '<br>';

これだけでは何のリンクなのか分かりません。引っ張るaタグの範囲を右カラムのリンクに絞ります。

// simple_html_dom.phpファイルの読み込み
include_once('simplehtmldom_1_5/simple_html_dom.php');
//スクレイピングしたいURLを指定
$html = file_get_html( 'http://www.kaasan.info/' );

//○○の中のある特定の要素もCSSと同じように指定できます。
foreach($html->find('#rightcol .category_list a') as $element)
echo $element->href . '<br>';
もちろん画像のみの抽出も可能でして
// simple_html_dom.phpファイルの読み込み
  include_once('simplehtmldom_1_5/simple_html_dom.php');
//スクレイピングしたいURLを指定
  $html = file_get_html( 'http://www.kaasan.info/' );
//画像URL保存用の空の配列を用意
  $src = array();
  //リンク
  foreach($html->find('img') as $key => $element){ 
  $src[$key] = $element->src;
  }

foreach($src as $img){
echo '<img src="'.$img.'">';
}

もっと細かく要素を指定したい場合はこちらが参考になります。

おまけ:Wordpress × Simple HTML Domでスクレイピング

スクレイピングしたDOMをforeachのループ中にINSERT文を実行すれば簡単に自分のwordpressに記事として登録することが出来ます。
以下はさくらvps設定マニュアルの投稿記事一覧を抽出してWordpressをインストールしたデータベースに、記事としてINSERTする方法です。

MDB2.phpは大手レンタルサーバーなら大抵インストールされているかと。(私mysql関数って使ったことないんですよ・・)

require_once 'MDB2.php';//ライブラリのロード
//DSN
  $db = "mysql://ユーザー名:パスワード@localhost/データベース名?charset=utf8";
//接続
  $mdb2 =& MDB2::factory($db);
//フェッチモード設定
  $mdb2->setFetchMode(MDB2_FETCHMODE_ASSOC);
  
  // simple_html_dom.phpファイルの読み込み
  include_once('simple_html_dom.php');
  
  // UTF-8で処理 他の文字コード処理するかもしれないからdefineしておく。
  define("CHAR_SET","UTF-8");
  
  // 文字化け対策のおまじない的(?)なもの。
  mb_language("Japanese");
  
  $html = file_get_html( 'http://www.kaasan.info/archives/category/さくらvps設定マニュアル' );
//wordpress上の投稿日時
  $wordpress['date'] = '2012-02-12 10:00:00';
foreach( $html->find( '#content ul' ) as $ul )
  foreach( $ul->find( 'li' ) as $li )
  $mdb2->exec("INSERT INTO `wp_posts` (`post_author`, `post_date`, `post_date_gmt`, `post_content`, `post_title`, `post_excerpt`, `post_status`, `comment_status`, `ping_status`, `post_password`, `post_name`, `to_ping`, `pinged`, `post_modified`, `post_modified_gmt`, `post_content_filtered`, `post_parent`, `menu_order`, `post_type`, `post_mime_type`, `comment_count`) VALUES
  (1, '{$wordpress['date']}', '{$wordpress['date']}', '$li', 'test', '', 'publish', 'open', 'open', '', 'test', '', '', '{$wordpress['date']}', '{$wordpress['date']}', '', 0, 0, 'post', '', 0)");

サンプルは以上です。
どこをどのように引っ張るのか、アイディア次第でいろんなサイトやサービスがお手軽に作れそうですが、著作権などの問題には十分注意してください。

PHPの配列で遊んでみる

RSSをもっと見やすく表示したい!

前回の記事でRSSをsimplexml_load_string関数を使ってRSSのXMLを表示してみました。でも、ちょっと見にくいし、分かりずらいので、自由に自分のほしいデータを持ってこれるように 配列構造を変更して、より配列に慣れ親しんでいこうと思います。
配列が分かればPHPが分かります。
ずばり、

配列を制するものは配列を制す!

です。

RSSを通常の配列の形に

前回の記事の最後の方にちょっとxmlオブジェクトのままだと扱いにくい点に触れましたが、
それならば扱いやすい配列の形に変換すればいいんです。
最初の2つのxmlオブジェクトとして展開するまでは前回と何も変わっていまん。
少し変わったのが、そのまま$xml->channel->item->$i->title;をechoで出力せず、
一度$rss[$i][‘title’]に代入してあげている点です。

連想配列に変換

実際に連想配列にする処理は以下。とってもシンプルですね。

//フィードを取得したいRSSのURLを記述
$contents = file_get_contents('http://www.kaasan.info/feed');
//XMLをオブジェクトに変換
$xml = simplexml_load_string($contents);
//連想配列作成用に、新規で空の配列を用意する
$rss = array();
for ($i = 0; $i <= 9; $i++) {
$rss[$i]['title'] = (string)$xml->channel->item->$i->title;
$rss[$i]['description'] = (string)$xml->channel->item->$i->description;
$rss[$i]['date'] = (string)$xml->channel->item->$i->pubDate;
$rss[$i]['link'] = (string)$xml->channel->item->$i->link;
}

解説

for文のループについては前回の記事を参考にしてもらうとして、大事なのが2つ。

・新規に配列を作る時は空の配列を用意する
・代入するxmlオブジェクトを(string) string(文字列)指定にする

まず配列とは、タンスのイメージです。
引き出しの中にデータが入ります。
ただの変数では引き出しがありません。
引き出しが無いなら空の配列を代入することで新たに引き出しを作ってあげればいいんですね。
たったコレだけ空の配列が出来、配列として代入することが出来るのです。
新たに配列を作りたいときには有効ですのでぜひ覚えて下さい。
RSSの配列代入イメージ

作った配列を出力してみる

作った配列をprint_rして出力してみましょう。
実行例
RSSをそのまま出力したものと比べるとぐっと見やすくなったのが分かりますか?
RSSをそのまま出力
$rssの出力
今まではrssの情報をすべて出力していましたが、今回新規で作った配列$rssは必要な部分だけ選んで配列化していますから、
とても見やすいですね。

RSSをHTMLの中に出力

最後の仕上げです。作った$rssをHTMLの中に書いて、きれいにRSSを表示してみましょう!
今回は非常に簡単だったのでループをもう一つ新しいものを覚えておきましょう。
foreach文です。

foreach文

for文は

for ($i = 0; $i <= 9; $i++){
echo ‘hogehoge';
}

としたように、$iがいくつから始まり,いくつまで繰り返すかを必ず指定しなければなりませんでしたが、
foreachはfor文と違い、問答無用で配列のある文だけループします。
たったこれだけです。初心者にはfor文が直感的で分かりやすいという意見もありますが、
PHPではforeachの方がやや実行が早いというメリットもありますので
for文の特性を利用した『配列中の何番目から何番目!』という決まりが無く、配列全て出力するのであればforeachを使うのがよいでしょう。

foreach($rss as $val)となっていたら、$valにデータを代入しているようなイメージでいてください。

foreachでの実行例

<dl>
<?php foreach($rss as $val):?>
<dt>
<a href="<?php echo $val['title'];?>">
タイトル:<?php echo $val['title'];?></a>
</dt>
<dd>ディスクリプション:<?php echo $val['description'];?></dd>
<dd>日付:<?php echo $val['date'];?></dd>
<?php endforeach;?>
</dl>

またはこんな書き方も出来ます。

<dl>
<?php foreach($rss as $val){ ?>

<dt><a href="<?php echo $val['title'];?>">タイトル:<?php echo $val['title'];?></a></dt>
<dd>ディスクリプション:<?php echo $val['description'];?></dd>
<dd>日付:<?php echo $val['date'];?></dd>
<?php } ?>
</dl>

ただ、これでは実際に } 閉じるタグがfor文の閉じタグなのかforeachの閉じタグなのかどちらなのか分からりにくいので個人的には上の方をオススメします。

これは何回目のループなのかを出したいなら

これは何回目のループなのかを出力したいなら、キー名の出力の仕方を覚えるとよいです。

<dl>
<?php foreach($rss as $key => $val):?>
<dt>第<?php echo $key;?>回目</dt>
<dt><a href="<?php echo $val['title'];?>">タイトル:<?php echo $val['title'];?></a></dt>
<dd>ディスクリプション:<?php echo $val['description'];?></dd>
<dd>日付:<?php echo $val['date'];?></dd>
<?php endforeach;?>
</dl>

実行例
以上でRSSの出力についてはおしまいです!

XMLとは?

2012年02月12日に開催したLinuxお勉強しよう会でPHPとXMLを使って遊ぼうというネタを紹介させて頂きました。
そこでのネタの詳しい解説としてまずはXMLとは何か?という根本的なところから初めていきます。

XMLとは?

XMLとは『コンピューターが認識するためのことば』です。
例えばHTMLはあくまでも人間が目で見て『これは何だ』と認識するものですが、コンピューターはHTMLを見ても内容を解析することは出来ません。
そこでXMLを利用するわけです。

XMLが利用されているところ

XMLの代表的な例はRSSがあります。
RSSとはブログなどの更新情報を配信などをしているところです。
RSSが配信されているサイトだと(このITかあさんのブログもRSSが配信されているのですが)このようにURLのアドレスバーにアイコンが表示されます
RSSが配信されているサイトのアドレスバー

ブラウザによって表示に誤差があるもののRSSをブラウザによって表示すると以下の画像のような表示になるかと思います。

このRSSをリーダーを使って購読するとこのようになります。
RSSをGoogleリーダーで購読した時の様子

RSSが配信されることのメリット

HTMLそのままだとレイアウトを変更するなりして、自分のサイトの一部分に組み込んだりすることは難しいですが、
RSSを配信することのメリットはGoogleリーダーで読み込んだり、自分のブログなどに設置して2次利用しやすくなります。
日本人はよほどIT企業に勤めていたりでもしなければRSSを購読してブログやサイトの更新情報をチェックする人は少ないかもしれません。しかもたくさんの人に購読されたからと言ってSEOに効果があるわけでもありません。
しかし、RSSはXMLという言語で作られているのでちょっとPHPをかじったレベルの人であればいとも簡単に自分のサイト内に表示させることが出来ます。
RSSというXML言語で作られたものを配信することによって誰かに2次利用してもらえることが期待出来、最終的にはめぐりめぐって自分のサイトのSEOに繋がるかもしれません。
そんなわけでPHPとXMLを使ったおもしろくて実用的なコンテンツの作り方を学びたいと思います。

RSSを自分のサイトに表示させる

PHPを使ってRSSを自分のサイトの好きなところに表示させてみよう

PHPを使ってRSSを自分のサイトやブログの好きなところに表示させてみたいと思います。
RSSはXMLという言語を使って出来ています。XMLについての詳しい解説はこちらを確認して下さい。

RSSをXMLとして表示する

RSSを表示してあげるには、
1.表示したいRSSのURLを指定するfile_get_contents関数
2.XMLとして開く関数を実行するsimplexml_load_string関数

$contents = file_get_contents('http://www.kaasan.info/feed');
$xml = simplexml_load_string($contents);

なんと、たったのこれだけで準備は完了です。
$xmlの中身がどうなっているのか、念のために参照してみます。
一つの変数($なんちゃら)に複数の値が入っているデータを配列をいうのですが、この配列構造になっているデータを参照するのに使う関数がprint_rまたはvar_dumpです。私も日ごろPHPで何かプログラミングをしていて、一番お世話になっている関数です。

$contents = file_get_contents('http://www.kaasan.info/feed');
$xml = simplexml_load_string($contents);
//$xmlの中身を参照。preタグで囲うと見やすくなる。
echo '<pre>';
print_r($xml);
echo '</pre>';

$xmlの中身を参照した時の実行結果

もしかしたらこの画面を見たことのある人もいるかもしれません。よくこれだけで『エラーです!どうにかしてください!』といわれるんですが、『あ、これ今デバック中なので・・・・』みたいなやりとりをよくWEBデザイナーの方としていますw
実はこの時点ですでにRSSをHTML内に表示する準備は出来ているんです。
細かい解説は後にして、ひとまず表示だけ先にしたいと思います。

HTML内にRSSを表示してみる

<dl>
<?php for($i = 0; $i <= 9; $i++):?>
<dt><a href="<?php echo $xml->channel->item->$i->link;?>" target="_blank"><?php echo $xml->channel->item->$i->title;?></a></dt>
<dd><?php echo $xml->channel->item->$i->description;?></dd>
<dd><?php echo $xml->channel->item->$i->pubDate;?></dd>
<?php endfor;?>
</dl>

実行結果

RSS表示の仕組みを解説

この画像は$xml->channel->itemの中身です。RSSの中身をprint_rしているURLと合わせて確認して下さい。
print_rで$xmlの中身を参照したとき、RSSをURLで確認して、件数を一つずつ数えると10件ありますが
PHPやJavascriptなどプログラミング言語では配列のカウントは0から数えるという大事な決まりごとがあります。

http://kaasan.biz/print_r.phpの参照

RSSをprint_rの参照結果

$xml->channel->itemの中身

$xml->channel->itemの中身

for文のループの仕組み

$xml->channel->itemの中身は分かっても、それがどういう仕組みでループされているかがピンと来ないかもしれません。私も生まれて初めてPHPでループをした時はピンときませんでした。

$iを出力してみる

そこで$iを出力しながら実行してみましょう。

<dl>
<?php for($i = 0; $i <= 9; $i++):?>
<dt>第<?php echo $i;?>番目のループ</dt>
<dt><a href="<?php echo $xml->channel->item->$i->link;?>" target="_blank"><?php echo $xml->channel->item->$i->title;?></a></dt>
<dd><?php echo $xml->channel->item->$i->description;?></dd>
<dd><?php echo $xml->channel->item->$i->pubDate;?></dd>
<?php endfor;?>
</dl>

実行結果

$xmlをprint_rで参照したものと、比べてみる

$xmlをprint_rで参照したものと、RSSの実行2を比べてみましょう。
$iには数字が1ずつ増加していることが2つを比べると理解できると思います。

好きなところだけ表示するには?

応用編として、好きなところだけを表示したいとします。例えば3番目から6番目。
(プログラム上、配列は0番目からカウントするのをお忘れなく)
for内の数字を変更すればいいだけです。

<dl>
<?php for($i = 3; $i <= 6; $i++):?>
<dt><a href="<?php echo $xml->channel->item->$i->link;?>" target="_blank"><?php echo $xml->channel->item->$i->title;?></a></dt>
<dd><?php echo $xml->channel->item->$i->description;?></dd>
<dd><?php echo $xml->channel->item->$i->pubDate;?></dd>
<?php endfor;?>
</dl>

逆順にしてみる

逆順にする方法もあります。配列の順番を入れ替える関数もあるんですが、もっと簡単に。
$i++で1ずつ増えるので$i–で1ずつマイナスにする方法もあるんです。
こうすればさっきと逆順になりますね!

//10番目から1ずつマイナスに
<dl>
<?php for($i = 9; $i <= 0; $i--):?>
<dt><a href="<?php echo $xml->channel->item->$i->link;?>" target="_blank"><?php echo $xml->channel->item->$i->title;?></a></dt>
<dd><?php echo $xml->channel->item->$i->description;?></dd>
<dd><?php echo $xml->channel->item->$i->pubDate;?></dd>
<?php endfor;?>
</dl>

最新1件だけ表示するには?

ループしないで最新1件だけがほしい!1件だけならループの必要がない?
最新1件だけのタイトルだけを出力するとして・・・

<?php echo $xml->channel->item->0->title;?>

どうでしょう?エラーですね。$ループされていたとき$inには数字が入っていたのだから、そのまま数字を書けばいいんじゃないの?
と思ってしまいますよね。これはちょっとした落とし穴でして。

->はオブジェクト(クラス)のメソッドやフィールド変数を参照するための演算子

演算子って言われてもイマイチピンときませんが、数字はあくまでも数字であることは分かりますよね。数字は数字。それ以上参照のしようがありませんものね。
オブジェクトでもなんでもないただの数字を展開しようとしたのでここではエラーになってしまったのです。
ちょっと面倒なのですが、この場合直前に$iに0を代入して、変数化してあげれば先ほどと同じ書き方で出力可能です。

<?php
$i = 0;
echo $xml->channel->item->0->title
; ?>

以上でRSSの基本的な出力方法についてはおしまいです。