カテゴリー : PHP

このカテゴリーの登録数:34件 表示 : 1 - 7 / 34

Mar 04, 2011

pdfファイルから表紙画像のjpgファイルを作る

ポスト @ 11:57:02 , 修正 @ Mar 04, 2011 2:57:02 | PHP

 pdf化された本も溜まってきた。pdfで買った本もある。だたファイルをフォルダに放り込んでおくだけでは、何があるのか判らなくなってしまう。電子書籍閲覧&管理ソフトを使えばいいのかも知れないけれど、どうも私の思うようには動いてくれない。Calibreはいろいろなファイル形式に対応して形式変換もできて素晴らしいのだが、私にもいろいろ事情があるのだ。

 文字情報としては、MySQLのデータベースとしてだいたい準備できた。しかし、表紙画像がない。本というものは表紙で覚えていたりするものだ。表紙画像一覧とか出てこないと困る。どうしても困る。そのためには、pdfファイルの第一頁だけをjpegに変換できたらいい。まあ、pngファイルなんかでもいいけれど。難しいのかなと思っていたが、何とImageMagickがインストールされていれば、

convert ebook.pdf[0] bkimg.jpg
とするだけでebook.pdfの表紙画像をbkimg.jpgというjpeg画像として出力できる。素晴らしい。

 今、私がやりたいことは、あるフォルダ(例えばebooksという名前)の中にあるpdfファイルと別のフォルダ(例えばimagesという名前)の中にあるjpegファイルを照合して、pdfファイルに対応するjpegファイルがなかったら、jpegファイルを作成するというスクリプトを書くということである。だが、私はシェルスクリプトは苦手なのだ。phpかpythonしか使えない。rubyは頑張ろうと思ったけれど、すぐに挫折。というわけでまずは、php5-imagickをインストールする。Ubuntuならapt-get install php5-imagickとするだけでいい。もとのpdfの大きさはさまざまだろうが、出力するjpegファイルは長辺が180pxになるように指定してやる。

foreach (glob("*.pdf") as $filename) {
  $jname = preg_replace("/\.pdf/",".jpg",$filename);
  $jnmpath = "/xxx/images/".$jname;
  if(!file_exists($jnmpath)){
  $img = new Imagick($filename);
  $img->setImageIndex(0);
  $img->thumbnailimage(180,180,true);
  $img->writeImage($jnmpath);
  $img->destroy();
  }
}

 ときどきこんなエラーが出るのだが、どういうことだろう。

Error: /undefined in findresource
Operand stack:
   --dict:9/18(L)--   C2_0   1   --dict:5/5(L)--   --dict:5/5(L)--   MSGothic   --dict:11/12(ro)(G)--   --nostringval--   CIDFontObject   --dict:7/7(L)--   --dict:7/7(L)--   Adobe-Japan1
Execution stack:
   %interp_exit   .runexec2   --nostringval--   --nostringval--   --nostringval--   2   %stopped_push   --nostringval--   --nostringval--   --nostringval--   false   1   %stopped_push   1878   1   3   %oparray_pop   1877   1   3   %oparray_pop   1861   1   3   %oparray_pop   --nostringval--   --nostringval--   305   1   306   --nostringval--   %for_pos_int_continue   --nostringval--   --nostringval--   --nostringval--   --nostringval--   %array_continue   --nostringval--   false   1   %stopped_push   --nostringval--   %loop_continue   --nostringval--   --nostringval--   --nostringval--   --nostringval--   --nostringval--   --nostringval--   %array_continue   --nostringval--   --nostringval--   --nostringval--   --nostringval--   --nostringval--   %loop_continue
Dictionary stack:
   --dict:1160/1684(ro)(G)--   --dict:1/20(G)--   --dict:75/200(L)--   --dict:75/200(L)--   --dict:108/127(ro)(G)--   --dict:287/300(ro)(G)--   --dict:22/25(L)--   --dict:6/8(L)--   --dict:26/40(L)--
Current allocation mode is local
Last OS error: 2
GPL Ghostscript 8.71: Unrecoverable error, exit code 1
Fatal error: Uncaught exception 'ImagickException' with message 'Postscript delegate failed `/tmp/magick-XX4zKuX7':  @ error/pdf.c/ReadPDFImage/645'

 仕方がないので、エラーが出たらそのファイルはconvertコマンドで手動で処理している。

Aug 03, 2009

GeekToolでニュースをデスクトップに

ポスト @ 19:23:57 , 修正 @ Aug 03, 2009 10:23:57 | PHP,MacOSX

 昨日書いたGeekToolですが、こいつを使ってニュースをデスクトップに表示させてみることにしました。ニュースを見に行って、つい余計な記事まで読んでしまうということはよくあるので、これで題名だけ見て、どうしても読みたい記事だけブラウザを開いて読むことにしよう。

 やることは簡単で、RSSで最新記事を配信している新聞社の情報をPHPで取得してタイトルを表示させるだけ。例えば朝日新聞なら、

<?php
$url = "http://rss.asahi.com/f/asahi_newsheadlines";
$rss = simplexml_load_file($url);
foreach($rss->item as $item){
  if(!ereg("AD: ",$item->title)){
    echo $item->title."\n";
  }
}
?>
という感じで。広告は外したかったので、「AD: 」で始まる項目は表示させませんでした。これを、asahi.phpとかいう名前で保存して、GeekToolのShellの一つとして指定してやればいい訳です。更新周期は10分にしました。もっと間隔を開けた方がいいかも。

asahi_news

 毎日新聞ならURLをhttp://mainichi.pheedo.jp/f/mainichijp_flashとすればいいだけですね。でも、私は日本経済新聞がいいな。ところが、日経はRSS配信をしていないのですよ。なんということだ。仕方がないので、「主要ニュース」のページからタイトルを取得するPHPスクリプトを書きましたよ。そんなことしている場合じゃないのに。

nikkei_news.jpg

 もちろん、外国のニュースだって表示できます。たとえば、ИЗВЕСТИЯなんかはどうですか。

$url = "http://rss.feedsportal.com/c/32171/f/424076/index.rss";
$rss = file_get_contents($url);
$rss = mb_convert_encoding($rss,"UTF-8");
$xml = simplexml_load_string($rss);
foreach($xml->channel->item as $item){
  echo $item->title;
  echo " (".substr($item->pubDate,18,5)." GMT)\n";
}
すると、こういうふうになるわけです。

izvestia

 これはいい! こうやってロシアのニュースが私のデスクトップに自動的に更新されつつ表示されるなんて。まったく何をやっているんだ、私は。読めもしないロシア語ニュースを表示させて喜んでどうするんだ。こんなことをしているから睡眠不足になって電車の中で倒れそうになるんじゃないか。莫迦か!

Jul 14, 2009

Amazon新刊RSSの作り直し

ポスト @ 8:11:56 , 修正 @ Jul 13, 2009 23:11:56 | Amazon,PHP

 気に入った作家の新刊を見逃していて3ヶ月くらい経ってから気づいて購入するのは妙に悔しい。もちろんそれで重大な損失があるわけでもないのだが、何となく大損した気分になるのは私だけだろうか。そんなわけで、気に入った作家の新刊情報を逃さないように、Amazon AWSの機能を使って新刊情報RSSを作っていた。xmlで得た結果をxsltスタイルシートで変換してRSSリーダで読んでいたのだが、この夏から Amazon Product Advertising APIと名前が変わるとともに、秘密鍵による認証とかタイムスタンプが必要になった。「Amazon Product Advertising API 電子署名とXSLTのまとめ」などを参考にして、あれこれやってみたがどうもうまく行かない。ふと気づいたのだが、うまくいったとしてもタイムスタンプが必要だから、毎回新しいURLを作ってやらなくてはならないではないか。RSSリーダにURLを登録しても駄目だと云うこと? 難しいことは苦手だが、私の理解ではそうなる。

 自分の努力がとてつもなく虚しく感じられてきたので、PHPで作ることにした。といっても、今までもPHPでもそういうのを作っていたから、認証のところを追加してやればいいだけである。細かい手順は前に書いたのと同じで、出力をRSSに整形してやればいいだけだ。トップページの右の方にURL作成の小窓を用意してみたが、そこにキーワードを入れるとRSSリーダに読ませるためのURLができあがる(はずだ)。

 ちなみに、Amazon.comだとhttp://www.amazon.com/rss/の後にtag/xxxx/newとか繋いでやれば、xxxxというタグのついた新着商品のRSSを作れる。少なくとも今のところは。

Jun 18, 2009

Amazon.co.jpのProduct Advertising APIのリクエストに認証のための電子署名を含める

ポスト @ 18:28:43 , 修正 @ Jun 18, 2009 9:28:43 | PHP,Amazon

 一昨日「Amazon.co.jp Product Advertising API チーム」というところから、メールが来て、「Product Advertising API への全てのリクエストに、認証のための電子署名を 2009年8月15日までに含めなければならない」ことを通知したのに、「弊社による調査では、お客様の AWSAccessKeyID から送信されているリクエストには、未だ電子署名が含まれていないことが判明しています」と警告されてしまった。ああ、そうだった。すっかり忘れていた。よく見たら、アメリカ、イギリス、ドイツ、フランスのAmazonから同じような警告が届いているではないか。面倒くさい。一体いくつのファイルを書き換えなければならないのか。気が遠くなるほどである。次から次へと訳もわからずPHPでスクリプトを書いては、cronで定期的に実行させたり、検索サイトを作ったりしてしまったのだ。

 とりあえず、一つでも進めておこう。この情報はネット上にたくさんあるので参考にできるところは多い。いろいろ参考にさせてもらって(一カ所でないので引用できないけど)、ISBNから作品情報を得る部分は次のようなfunctionを作って今までのPHPスクリプトに埋め込み、Amazon.co.jpへの問い合わせの部分を置き換えることにした。

function amzuri($asin)
  {
  $params = array();
  $params['Service'] = "AWSECommerceService";
  $params['AWSAccessKeyId'] = "xxxxxxxxxxxxxxxxxx";
  $params['Version'] = "2009-03-31";
  $params['Operation'] = "ItemLookup";
  $params['Timestamp'] = gmdate('Y-m-d\TH:i:s\Z');
  $params['ItemId'] = $asin;
  $params['ResponseGroup'] = "Small";
  ksort($params);
  $canonical_string = '';
  foreach ($params as $k => $v) {
    $canonical_string .= '&'.rawurlencode($k).'='.rawurlencode($v);
  }
  $canonical_string = substr($canonical_string, 1);
  $baseurl = "http://ecs.amazonaws.jp/onca/xml";
  $SecretKey = "xxxxxxxxxxxxxxxxxx/xxxxxxxx";
  $parsed_url = parse_url($baseurl);
  $string_to_sign = "GET\n{$parsed_url['host']}\n{$parsed_url['path']}\n{$canonical_string}";
  $signature = base64_encode(hash_hmac('sha256', $string_to_sign, $SecretKey, true));
  $amzurl = $baseurl.'?'.$canonical_string.'&Signature='.rawurlencode($signature);
  return $amzurl;
  }
$getamz = amzuri($asin);
$res = simplexml_load_file($getamz);
foreach($res->Items->Item as $item){
$amazon = $item->DetailPageURL;
}

 これで、試してみたら、いちおう答えが返ってきたからいいのだろうか。今は認証ができていなくてもエラーはでないのか。だとしたら、8月15日に一斉にエラーが出ると大変困ったことになる。

 次にタイトルに含まれるキーワードで今月(以前)に出る本を検索し、その結果を新しい順に並べるというものである。

function amzuri($keyword,$pdate)
  {
  $params = array();
  $params['Service'] = "AWSECommerceService";
  $params['AWSAccessKeyId'] = "xxxxxxxxxxxxxxxxxxx";
  $params['Version'] = "2009-03-31";
  $params['Operation'] = "ItemSearch";
  $params['Timestamp'] = gmdate('Y-m-d\TH:i:s\Z');
  $params['ResponseGroup'] = "Medium,Offers";
  $params['SearchIndex'] = "Books";
  $params['Sort'] = "-publication_date";
  $params['Power'] = "pubdate:before ".$pdate." and title:".$keyword;
  ksort($params);
  $canonical_string = '';
  foreach ($params as $k => $v) {
    $canonical_string .= '&'.rawurlencode($k).'='.rawurlencode($v);
  }
  $canonical_string = substr($canonical_string, 1);
  $baseurl = "http://ecs.amazonaws.jp/onca/xml";
  $SecretKey = "xxxxxxxxxxxxxxxxxxxx/xxxxxxxxx";
  $parsed_url = parse_url($baseurl);
  $string_to_sign = "GET\n{$parsed_url['host']}\n{$parsed_url['path']}\n{$canonical_string}";
  $signature = base64_encode(hash_hmac('sha256', $string_to_sign, $SecretKey, true));
  $amzurl = $baseurl.'?'.$canonical_string.'&Signature='.rawurlencode($signature);
  return $amzurl;
  }

 いいのかなあ。これを5カ国分やらなければならないのか。まあ、9割はAmazon.co.jpだと思うけど。

Apr 26, 2009

iPhone Simulatorを使ってみる

ポスト @ 18:46:13 , 修正 @ Apr 26, 2009 9:46:13 | MacOSX,PHP

iPhone Simulator 先日、iPhone Web Style (2800円+税/ソフトバンククリエイティブ)[amazon.co.jp, bk1, 楽天, 紀伊國屋書店, Yahoo! Books]なんていう本を買って、iPhone/iPodTouchで見てもらいやすい画面構成について考えていたのだが、私はiPhoneもiPhodTouchも持っていないのだ。どんなふうに見えるか判らないから改良のしようもない。そこで、iPhone Simulatorを使ってみることにした。まず、iPhone SDKをiPhone Developerサイトからダウンロードする。これには登録が必要だが、無料なので心配しなくても大丈夫だ。アプリケーションを作って販売しようなんていうときは有償のプログラムに登録しなければならないが、サイトを作るだけならその必要はないからだ。私は前からApple Developerとして登録していたのだけど、それでは駄目なようで、改めてiPhone Developerとして登録しなければならない。そしてiPhone SDKをダウンロード。いつものアップルのアプリケーションのようにインストールする。ルートディレクトリのDeveloperにインストールされる。その中の、Platforms→iPhoneSimulator.platform→Developer→Applications→iPhone Simulator.appが、今求めているアプリケーションである。これをダブルクリックで立ち上げればいい。

 私が確認したかったのは、自分の読書日記がどう見えるかということ。WX340KのNetFrontで見たら、延々と左の年ごとに月をクリックする領域が続いて、なかなか日記本文に辿り着かなかった悲しい事実に直面し、何とかこれを改良しようと思ったのである。尤も、iPhone/iPodTouchのSafariはそこまでひどくない。でも、なるべく読みやすくしたいから。

 私のサイトは主にPHPで構築されているので、まずはブラウザ情報をPHPで取得する方法を調べてみると、$_SERVER['HTTP_USER_AGENT']で簡単に取得できると判った。iPhone、iPod、NetFrontの文字がそこに含まれていたら、左のカラムを読み込まないようにした。

$browser = $_SERVER['HTTP_USER_AGENT'];
if(!ereg("iPhone|iPod|NetFront",$browser)){
  include ("leftcolumn.html");
}
といった具合に。これで、まあNetFrontだとすぐに日記が読めるのだけど、iPhone/iPodTouchのSafariはきちんとcssを処理するので、左側に無駄な空白が残ってしまう。専用のcssを用意してやろう。そこで、最初の方に、
<?php
$browser = $_SERVER['HTTP_USER_AGENT'];
if(ereg("iPhone|iPod",$browser)){
echo " <link rel=\"stylesheet\" href=\"iphone.css\" type=\"text/css\" />";
}else{
echo " <link rel=\"stylesheet\" href=\"diary.css\" type=\"text/css\" />";
}
?>
と書いてみた。最新10件を表示する画面RSSで更新情報を得てから一日分の記事を読むページである。左のカラムがなくなると、その後どこにも移動できなくなるので、前日の記事や翌日の記事へのリンクを最後に付けた。その画面の確認が、こんなふうにできる。

diary with iphone/ipod touch

 前よりは読みやすくなっただろうか。尤も、今のところiPhone/iPod Touchで私の日記を読んでくれている人はほとんどいない。NetFrontも。でも、これを機会に読んでくれる人が一人でも増えれば嬉しい。

Apr 18, 2009

PowerEdge T100で自宅サーバ復帰

ポスト @ 23:45:32 , 修正 @ Apr 18, 2009 14:45:32 | ubuntu,PHP,その他

 何度やっても忘れてしまうので、こうやって記録を残すよう心がけているのだが、結局自分の書いたメモを読まずに、Googleなんかで検索して人の記録を参照している自分に気づく今日この頃ですが、皆さんは自分のメモをきちんと読んでいるのでしょうか。

 まずは、開発環境をインストール。

sudo apt-get install build-essential
sudo apt-get install libtool
 次に、LAMPの二文字目以降。LinuxはすでにUbuntu設定済みなので。まずApache2から。
sudo apt-get install apache2
http://192.168.xxx.xxxをブラウザで開いて、「It works!」の表示を確認。次にPHP5。
sudo apt-get install php5 libapache2-mod-php5
sudo /etc/init.d/apache2 restartとやってApacheの再起動。その後にMySQL。
sudo apt-get install mysql-server
 途中でrootのパスワードを訊ねられるので、設定。Sourceから自分でコンパイルすると、この設定やデータベースの初期化なども自分でやらなければならない。

 MySQLの名前もパスワードもないユーザを削除する。

mysql > delete from user where User = '';
mysql> GRANT ALL PRIVILEGES ON *.* TO 'monty'@'localhost'
    ->     IDENTIFIED BY 'password';
mysql> FLUSH PRIVILEGES;
/etc/mysql/my.cnfを開いて、[mysqld]に
default-character-set = utf8
skip-character-set-client-handshake
を追加。

 sudo /etc/init.d/mysql restartとやって再起動すると、

$ sudo /etc/init.d/mysql restart
* Stopping MySQL database server mysqld [ OK ]
* Starting MySQL database server mysqld [ OK ]
* Checking for corrupt, not cleanly closed and upgrade needing tables.
という表示が出て、まるで正しく閉じなかったからテーブルのアップグレードが必要だという警告であるかのように驚くが、 これはテーブルが壊れていないか、正しく閉じていたか、アップグレードが必要かチェックしていますという表示らしい。 そういう解釈で本当にいいのか。
mysql> show variables like "char%";
+--------------------------+---------------------------+
| Variable_name            | Value                     |
+--------------------------+---------------------------+
| character_set_client     | utf8                      | 
| character_set_connection | utf8                      | 
| character_set_database   | utf8                      | 
| character_set_filesystem | binary                    | 
| character_set_results    | utf8                      | 
| character_set_server     | utf8                      | 
| character_set_system     | utf8                      | 
| character_sets_dir       | /usr/local/mysql/charsets/| 
+--------------------------+---------------------------+
8 rows in set (0.00 sec)
という表示が出て、文字コードがutf8に設定されたことを確認。

 phpmyadminをインストール。phpとapache2とmysqlの連携に必要なものがインストールされるのでちょうどいい。http://xxx.xxx.xxx.xxx/phpmyadmin/をブラウザで開いて、mysqlのユーザ名とパスワードでログインできることを確認する。

 /etc/php5/apache2/php.iniを開いて、

magic_quotes_gpc Off
default_charset = "UTF-8"
と変えてみた。2行目は必要あるのか。
[mbstring]のところを、
mbstring.language = Japanese
mbstring.internal_encoding = UTF-8
mbstring.http_input = auto
mbstring.http_output = pass
mbstring.encoding_translation = Off
mbstring.detect_order = auto
mbstring.substitute_character = none;
とコメントアウトの印の;を外して書き換える。意味がもう判らなくなっているものもある。

 これだけだとphpスクリプトが動かせない。php xxx.phpとやっても、プログラム'php'がまだインストールされていませんよという警告が出てしまうので、

sudo apt-get install php5-cli
というようにインストールする。

/etc/php5/cli/php.iniも開いて、文字コード関係など書き換える。

 rubyをインストール。すなわち、python-mySQLdbとlibapache2-mod-pythonを。

 /home/***/public_htmlを使えるようにする。

cd /etc/apache2/mods-enabled
sudo ln -s ../mods-available/userdir.conf userdir.conf
sudo ln -s ../mods-available/userdir.load userdir.load
public_htmlというディレクトリがなかったので、作る。

 Virtual hostの設定。もともとubuntuのapache2ではヴァーチャル・ホストとして設定されているので、ディレクトリを指定するだけでいい。
/etc/apache2/sites-available/default
を開くと


 ServerAdmin webmaster@localhost
   DocumentRoot /var/www
   ....
となっているので、

   ServerName nakano.no-ip.org
   ServerAdmin webmaster@localhost
   DocumentRoot /var/www/xxx
   ....

と書けばここのドメインが有効になる。二つ目、三つ目を、

   ServerName xxx.xxx.com
 ServerAdmin virtual@mail
   DocumentRoot /var/www/yyy
   ....

と増やしていけばいい。

 これでApacheを再起動したあとに、IPアドレスでアクセスすると、一番上のVirtualHostにアクセスする。/var/www直下に置かれたファイルにはアクセスできなくなる。

Apr 13, 2009

MacOSXにGD付きPHPをインストールしたかった

ポスト @ 23:53:27 | MacOSX,PHP

 Mac OS X 10.5には、Apache 2もPHP 5もインストールされている。MySQLもユーザ名が登録済みなので、インストールするだけである。しかし、PHPにはGDが組み込まれていない。libjpeg、libpng、Freetype2をまずインストールして、それからGD。部分的にPHPをコンパイルしようとしたが、MySQLの設定があまり現実と合っていないようなので、両方sourceからコンパイルして入れようと思ったわけだ。どんどん泥沼にはまっていき、最後は、

/usr/share/apr-1/build-1/libtool --mode=install cp libs/libphp5.so /usr/libexec/apache2/
cp libs/libphp5.so /usr/libexec/apache2/libphp5.so
Warning!  dlname not found in /usr/libexec/apache2/libphp5.so.
Assuming installing a .so rather than a libtool archive.
chmod 755 /usr/libexec/apache2/libphp5.so
というエラーでにっちもさっちも行かなくなる。もうどうしようもない。ああ、一日を棒に振ってしまった。今日は詳細を書く元気もない。