OSDN Git Service

初回コミット(v2.6.17.1)
[magic3/magic3.git] / widgets / wiki_main / include / plugin / amazon.inc.php
1 <?php
2 /**
3  * amazonプラグイン
4  *
5  * 機能:テキストに色を付ける。
6  *
7  * PHP versions 5
8  *
9  * LICENSE: This source file is licensed under the terms of the GNU General Public License.
10  *
11  * @package    Magic3 Framework
12  * @author     平田直毅(Naoki Hirata) <naoki@aplo.co.jp>
13  * @copyright  Copyright 2006-2009 Magic3 Project.
14  * @license    http://www.gnu.org/copyleft/gpl.html  GPL License
15  * @version    SVN: $Id: amazon.inc.php 3474 2010-08-13 10:36:48Z fishbone $
16  * @link       http://www.magic3.org
17  */
18 // Amazon plugin: Book-review maker via amazon.com/amazon.jp
19 //
20 // Copyright:
21 //      2004-2005 PukiWiki Developers Team
22 //      2003 閑舎 <raku@rakunet.org> (Original author)
23 //
24 // License: GNU/GPL
25 //
26 // ChangeLog:
27 // * 2004/04/03 PukiWiki Developer Team (arino <arino@users.sourceforge.jp>)
28 //        - replace plugin_amazon_get_page().
29 //        - PLUGIN_AMAZON_XML 'xml.amazon.com' -> 'xml.amazon.co.jp'
30 // * 0.6  URL が存在しない場合、No image を表示、画像配置など修正。
31 //        インラインプラグインの呼び出し方を修正。
32 //        ASIN 番号部分をチェックする。
33 //        画像、タイトルのキャッシュによる速度の大幅アップ。
34 // * 0.7  ブックレビュー生成のデバッグ、認証問題の一応のクリア。
35 // * 0.8  amazon 全商品の画像を表示。
36 //        アソシエイト ID に対応。
37 // * 0.9  RedHat9+php4.3.2+apache2.0.46 で画像が途中までしか読み込まれない問題に対処。
38 //        日本語ページの下にブックレビューを作ろうとすると文字化けして作れない問題の解決。
39 //        書籍でなく CD など、ASIN 部分が長くてもタイトルをうまく拾うようにする。
40 //        写影のみ取り込むのでなければ、B000002G6J.01 と書かず B000002G6J と書いても写影が出るようにする。
41 //        ASIN に対応するキャッシュ画像/キャッシュタイトルをそれぞれ削除する機能追加。
42 //        proxy 対応(試験的)。
43 //        proxy 実装の過程で一般ユーザのための AID はなくとも自動生成されることがわかり、削除した。
44 // * 1.0  ブックレビューでなく、レビューとする。
45 //        画像のキャッシュを削除する期限を設ける。
46 //        タイトル、写影を Web Services の XML アクセスの方法によって get することで時間を短縮する。
47 //        レビューページ生成のタイミングについて注を入れる。
48 // * 1.1  編集制限をかけている場合、部外者がレビューを作ろうとして、ページはできないが ASIN4774110655.tit などのキャッシュができるのを解決。
49 //        画像の最後が 01 の場合、image を削除すると noimage.jpg となってしまうバグを修正。
50 //        1.0 で導入した XML アクセスは高速だが、返す画像情報がウソなので、09 がだめなら 01 をトライする、で暫定的に解決。
51 //
52 // Caution!:
53 // * 著作権が関連する為、www.amazon.co.jp のアソシエイトプログラムを確認の上ご利用下さい。
54 // * レビューは、amazon プラグインが呼び出す編集画面はもう出来て PukiWiki に登録されているので、
55 //   中止するなら全文を削除してページの更新ボタンを押すこと。
56 // * 下の PLUGIN_AMAZON_AID、PROXY サーバの部分、expire の部分を適当に編集して使用してください(他はそのままでも Ok)。
57 //
58 // Thanks to: Reimy and PukiWiki Developers Team
59 //
60
61 /////////////////////////////////////////////////
62 // Settings
63
64 // Amazon associate ID
65 //define('PLUGIN_AMAZON_AID',''); // None
66 define('PLUGIN_AMAZON_AID','');
67
68 // Expire caches per ? days
69 define('PLUGIN_AMAZON_EXPIRE_IMAGECACHE',   1);
70 define('PLUGIN_AMAZON_EXPIRE_TITLECACHE', 356);
71
72 // Alternative image for 'Image not found'
73 define('PLUGIN_AMAZON_NO_IMAGE', IMAGE_DIR . 'noimage.png');
74
75 // URI prefixes
76 switch(LANG){
77 case 'ja':
78         // Amazon shop
79         define('PLUGIN_AMAZON_SHOP_URI', 'http://www.amazon.co.jp/exec/obidos/ASIN/');
80
81         // Amazon information inquiry (dev-t = default value in the manual)
82         define('PLUGIN_AMAZON_XML', 'http://xml.amazon.co.jp/onca/xml3?t=webservices-20&' .
83                 'dev-t=GTYDRES564THU&type=lite&page=1&f=xml&locale=jp&AsinSearch=');
84         break;
85 default:
86         // Amazon shop
87         define('PLUGIN_AMAZON_SHOP_URI', 'http://www.amazon.com/exec/obidos/ASIN/');
88
89         // Amazon information inquiry (dev-t = default value in the manual)
90         define('PLUGIN_AMAZON_XML', 'http://xml.amazon.com/onca/xml3?t=webservices-20&' .
91                 'dev-t=GTYDRES564THU&type=lite&page=1&f=xml&locale=us&AsinSearch=');
92         break;
93 }
94
95 /////////////////////////////////////////////////
96
97 function plugin_amazon_init()
98 {
99         global $amazon_aid, $amazon_body;
100
101         if (PLUGIN_AMAZON_AID == '') {
102                 $amazon_aid = '';
103         } else {
104                 $amazon_aid = PLUGIN_AMAZON_AID . '/';
105         }
106         $amazon_body = <<<EOD
107 -作者: [[ここ編集のこと]]
108 -評者: お名前
109 -日付: &date;
110 **お薦め対象
111 [[ここ編集のこと]]
112
113 #amazon(,clear)
114 **感想
115 [[ここ編集のこと]]
116
117 // まず、このレビューを止める場合、全文を削除し、ページの[更新ボタン]を押してください!(PukiWiki にはもう登録されています)
118 // 続けるなら、上の、[[ここ編集のこと]]部分を括弧を含めて削除し、書き直してください。
119 // お名前、部分はご自分の名前に変更してください。私だと、閑舎、です。
120 // **お薦め対象、より上は、新しい行を追加しないでください。目次作成に使用するので。
121 // //で始まるコメント行は、最終的に全部カットしてください。目次が正常に作成できない可能性があります。
122 #comment
123 EOD;
124 }
125
126 function plugin_amazon_convert()
127 {
128         //global $script, $vars, $asin, $asin_all;
129         global $asin, $asin_all;
130
131         if (func_num_args() > 3) {
132                 if (PKWK_READONLY) return ''; // Show nothing
133
134                 return '#amazon([ASIN-number][,left|,right]' .
135                         '[,book-title|,image|,delimage|,deltitle|,delete])';
136
137         } else if (func_num_args() == 0) {
138                 // レビュー作成
139                 if (PKWK_READONLY) return ''; // Show nothing
140
141                 /*$s_page = htmlspecialchars($vars['page']);
142                 if ($s_page == '') $s_page = isset($vars['refer']) ? $vars['refer'] : '';*/
143                 $s_page = htmlspecialchars(WikiParam::getPage());
144                 if ($s_page == '') $s_page = WikiParam::getRefer();
145                 $script = get_script_uri() . WikiParam::convQuery('?');
146                 $ret = <<<EOD
147 <form action="$script" method="post" class="form">
148  <div>
149   <input type="hidden" name="plugin" value="amazon" />
150   <input type="hidden" name="refer" value="$s_page" />
151   ASIN:
152   <input type="text" name="asin" size="30" value="" />
153   <input type="submit" class="button" value="レビュー編集" /> (ISBN 10 桁 or ASIN 12 桁)
154  </div>
155 </form>
156 EOD;
157                 return $ret;
158         }
159
160         $aryargs = func_get_args();
161
162         $align = strtolower($aryargs[1]);
163         if ($align == 'clear') return '<div style="clear:both"></div>'; // 改行挿入
164         if ($align != 'left') $align = 'right'; // 配置決定
165
166         $asin_all = htmlspecialchars($aryargs[0]);  // for XSS
167         if (is_asin() == FALSE && $align != 'clear') return FALSE;
168
169         if ($aryargs[2] != '') {
170                 // タイトル指定
171                 $title = $alt = htmlspecialchars($aryargs[2]); // for XSS
172                 if ($alt == 'image') {
173                         $alt = plugin_amazon_get_asin_title();
174                         if ($alt == '') return FALSE;
175                         $title = '';
176                 } else if ($alt == 'delimage') {
177                         if (unlink(CACHE_DIR . 'ASIN' . $asin . '.jpg')) {
178                                 return 'Image of ' . $asin . ' deleted...';
179                         } else {
180                                 return 'Image of ' . $asin . ' NOT DELETED...';
181                         }
182                 } elseif ($alt == 'deltitle') {
183                         if (unlink(CACHE_DIR . 'ASIN' . $asin . '.tit')) {
184                                 return 'Title of ' . $asin . ' deleted...';
185                         } else {
186                                 return 'Title of ' . $asin . ' NOT DELETED...';
187                         }
188                 } elseif ($alt == 'delete') {
189                         if ((unlink(CACHE_DIR . 'ASIN' . $asin . '.jpg') &&
190                              unlink(CACHE_DIR . 'ASIN' . $asin . '.tit'))) {
191                                 return 'Title and Image of ' . $asin . ' deleted...';
192                         } else {
193                                 return 'Title and Image of ' . $asin . ' NOT DELETED...';
194                         }
195                 }
196         } else {
197                 // タイトル自動取得
198                 $alt = $title = plugin_amazon_get_asin_title();
199                 if ($alt == '') return FALSE;
200         }
201
202         return plugin_amazon_print_object($align, $alt, $title);
203 }
204
205 function plugin_amazon_action()
206 {
207         //global $vars, $script, $edit_auth, $edit_auth_users;
208         global $edit_auth, $edit_auth_users;
209         global $amazon_body, $asin, $asin_all;
210
211         if (PKWK_READONLY) die_message('PKWK_READONLY prohibits editing');
212
213         //$s_page   = isset($vars['refer']) ? $vars['refer'] : '';
214         $s_page   = WikiParam::getRefer();
215         //$asin_all = isset($vars['asin']) ? htmlspecialchars(rawurlencode(strip_bracket($vars['asin']))) : '';
216         $asin_all = (WikiParam::getVar('asin') != '') ? htmlspecialchars(rawurlencode(strip_bracket(WikiParam::getVar('asin')))) : '';
217
218         if (! is_asin()) {
219                 $retvars['msg']   = 'ブックレビュー編集';
220                 $retvars['refer'] = $s_page;
221                 $retvars['body']  = plugin_amazon_convert();
222                 return $retvars;
223
224         } else {
225                 $r_page     = $s_page . '/' . $asin;
226                 $r_page_url = rawurlencode($r_page);
227                 $auth_user = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : '';
228
229                 pkwk_headers_sent();
230                 if ($edit_auth && ($auth_user == '' || ! isset($edit_auth_users[$auth_user]) ||
231                     $edit_auth_users[$auth_user] != $_SERVER['PHP_AUTH_PW'])) {
232                         // Edit-auth failed. Just look the page
233                         //header('Location: ' . get_script_uri() . '?' . $r_page_url);
234                         header('Location: ' . get_script_uri() . WikiParam::convQuery('?' . $r_page_url, false));
235                 } else {
236                         $title = plugin_amazon_get_asin_title();
237                         if ($title == '' || preg_match('#^/#', $s_page)) {
238                                 // Invalid page name
239                                 //header('Location: ' . get_script_uri() . '?' . rawurlencode($s_page));
240                                 header('Location: ' . get_script_uri() . WikiParam::convQuery('?' . rawurlencode($s_page), false));
241                         } else {
242                                 $body = '#amazon(' . $asin_all . ',,image)' . "\n" .
243                                         '*' . $title . "\n" . $amazon_body;
244                                 plugin_amazon_review_save($r_page, $body);
245                                 //header('Location: ' . get_script_uri() . '?cmd=edit&page=' . $r_page_url);
246                                 header('Location: ' . get_script_uri() . WikiParam::convQuery('?cmd=edit&page=' . $r_page_url, false));
247                         }
248                 }
249                 exit;
250         }
251 }
252
253 function plugin_amazon_inline()
254 {
255         global $amazon_aid, $asin, $asin_all;
256
257         list($asin_all) = func_get_args();
258
259         $asin_all = htmlspecialchars($asin_all); // for XSS
260         if (! is_asin()) return FALSE;
261
262         $title = plugin_amazon_get_asin_title();
263         if ($title == '') {
264                 return FALSE;
265         } else {
266                 return '<a href="' . PLUGIN_AMAZON_SHOP_URI .
267                         $asin . '/' . $amazon_aid . 'ref=nosim">' . $title . '</a>' . "\n";
268         }
269 }
270
271 function plugin_amazon_print_object($align, $alt, $title)
272 {
273         global $amazon_aid;
274         global $asin, $asin_ext, $asin_all;
275
276         $url      = plugin_amazon_cache_image_fetch(CACHE_DIR);
277         $url_shop = PLUGIN_AMAZON_SHOP_URI . $asin . '/' . $amazon_aid . 'ref=nosim';
278         $center   = 'text-align:center';
279
280         if ($title == '') {
281                 // Show image only
282                 $div  = '<div style="float:' . $align . ';margin:16px 16px 16px 16px;' . $center . '">' . "\n";
283                 $div .= ' <a href="' . $url_shop . '"><img src="' . $url . '" alt="' . $alt . '" /></a>' . "\n";
284                 $div .= '</div>' . "\n";
285
286         } else {
287                 // Show image and title
288                 $div  = '<div style="float:' . $align . ';padding:.5em 1.5em .5em 1.5em;' . $center . '">' . "\n";
289                 $div .= ' <table style="width:110px;border:0;' . $center . '">' . "\n";
290                 $div .= '  <tr><td style="' . $center . '">' . "\n";
291                 $div .= '   <a href="' . $url_shop . '"><img src="' . $url . '" alt="' . $alt  .'" /></a></td></tr>' . "\n";
292                 $div .= '  <tr><td style="' . $center . '"><a href="' . $url_shop . '">' . $title . '</a></td></tr>' . "\n";
293                 $div .= ' </table>' . "\n";
294                 $div .= '</div>' . "\n";
295         }
296         return $div;
297 }
298
299 function plugin_amazon_get_asin_title()
300 {
301         global $asin, $asin_ext, $asin_all;
302
303         if ($asin_all == '') return '';
304
305         $nocache = $nocachable = 0;
306
307         $url = PLUGIN_AMAZON_XML . $asin;
308
309         if (file_exists(CACHE_DIR) === FALSE || is_writable(CACHE_DIR) === FALSE) $nocachable = 1; // キャッシュ不可の場合
310
311         if (($title = plugin_amazon_cache_title_fetch(CACHE_DIR)) == FALSE) {
312                 $nocache = 1; // キャッシュ見つからず
313                 $body    = plugin_amazon_get_page($url); // しかたないので取りにいく
314                 $tmpary  = array();
315                 $body    = mb_convert_encoding($body, SOURCE_ENCODING, 'UTF-8');
316                 preg_match('/<ProductName>([^<]*)</', $body, $tmpary);
317                 $title     = trim($tmpary[1]);
318 //              $tmpary[1] = '';
319 //              preg_match('#<ImageUrlMedium>http://images-jp.amazon.com/images/P/[^.]+\.(..)\.#',
320 //                      $body, $tmpary);
321 //              if ($tmpary[1] != '') {
322 //                      $asin_ext = $tmpary[1];
323 //                      $asin_all = $asin . $asin_ext;
324 //              }
325         }
326
327         if ($title == '') {
328                 return '';
329         } else {
330                 if ($nocache == 1 && $nocachable != 1)
331                         plugin_amazon_cache_title_save($title, CACHE_DIR);
332                 return $title;
333         }
334 }
335
336 // タイトルキャッシュがあるか調べる
337 function plugin_amazon_cache_title_fetch($dir)
338 {
339         global $asin, $asin_ext, $asin_all;
340
341         $filename = $dir . 'ASIN' . $asin . '.tit';
342
343         $get_tit = 0;
344         if (! is_readable($filename)) {
345                 $get_tit = 1;
346         } elseif (PLUGIN_AMAZON_EXPIRE_TITLECACHE * 3600 * 24 < time() - filemtime($filename)) {
347                 $get_tit = 1;
348         }
349
350         if ($get_tit) return FALSE;
351
352         if (($fp = @fopen($filename, 'r')) === FALSE) return FALSE;
353         $title = fgets($fp, 4096);
354 //      $tmp_ext = fgets($fp, 4096);
355 //      if ($tmp_ext != '') $asin_ext = $tmp_ext;
356         fclose($fp);
357
358         if (strlen($title) > 0) {
359                 return $title;
360         } else {
361                 return FALSE;
362         }
363 }
364
365 // 画像キャッシュがあるか調べる
366 function plugin_amazon_cache_image_fetch($dir)
367 {
368         global $asin, $asin_ext, $asin_all;
369
370         $filename = $dir . 'ASIN' . $asin . '.jpg';
371
372         $get_img = 0;
373         if (! is_readable($filename)) {
374                 $get_img = 1;
375         } elseif (PLUGIN_AMAZON_EXPIRE_IMAGECACHE * 3600 * 24 < time() - filemtime($filename)) {
376                 $get_img = 1;
377         }
378
379         if ($get_img) {
380                 $url = 'http://images-jp.amazon.com/images/P/' . $asin . '.' . $asin_ext . '.MZZZZZZZ.jpg';
381                 if (! is_url($url)) return FALSE;
382
383                 $body = plugin_amazon_get_page($url);
384                 if ($body != '') {
385                         $tmpfile = $dir . 'ASIN' . $asin . '.jpg.0';
386                         $fp = fopen($tmpfile, 'wb');
387                         fwrite($fp, $body);
388                         fclose($fp);
389                         $size = getimagesize($tmpfile);
390                         unlink($tmpfile);
391                 }
392                 if ($body == '' || $size[1] <= 1) { // 通常は1が返るが念のため0の場合も(reimy)
393                         // キャッシュを PLUGIN_AMAZON_NO_IMAGE のコピーとする
394                         if ($asin_ext == '09') {
395                                 $url = 'http://images-jp.amazon.com/images/P/' . $asin . '.01.MZZZZZZZ.jpg';
396                                 $body = plugin_amazon_get_page($url);
397                                 if ($body != '') {
398                                         $tmpfile = $dir . 'ASIN' . $asin . '.jpg.0';
399                                         $fp = fopen($tmpfile, 'wb');
400                                         fwrite($fp, $body);
401                                         fclose($fp);
402                                         $size = getimagesize($tmpfile);
403                                         unlink($tmpfile);
404                                 }
405                         }
406                         if ($body == '' || $size[1] <= 1) {
407                                 $fp = fopen(PLUGIN_AMAZON_NO_IMAGE, 'rb');
408                                 if (! $fp) return FALSE;
409                                 
410                                 $body = '';
411                                 while (! feof($fp)) $body .= fread($fp, 4096);
412                                 fclose ($fp);
413                         }
414                 }
415                 plugin_amazon_cache_image_save($body, CACHE_DIR);
416         }
417         return $filename;
418 }
419
420 // Save title cache
421 function plugin_amazon_cache_title_save($data, $dir)
422 {
423         global $asin, $asin_ext, $asin_all;
424
425         $filename = $dir . 'ASIN' . $asin . '.tit';
426         $fp = fopen($filename, 'w');
427         fwrite($fp, $data);
428         fclose($fp);
429
430         return $filename;
431 }
432
433 // Save image cache
434 function plugin_amazon_cache_image_save($data, $dir)
435 {
436         global $asin, $asin_ext, $asin_all;
437
438         $filename = $dir . 'ASIN' . $asin . '.jpg';
439         $fp = fopen($filename, 'wb');
440         fwrite($fp, $data);
441         fclose($fp);
442
443         return $filename;
444 }
445
446 // Save book data
447 function plugin_amazon_review_save($page, $data)
448 {
449         global $asin, $asin_ext, $asin_all;
450
451         $filename = DATA_DIR . encode($page) . '.txt';
452         if (! is_readable($filename)) {
453                 $fp = fopen($filename, 'w');
454                 fwrite($fp, $data);
455                 fclose($fp);
456                 return TRUE;
457         } else {
458                 return FALSE;
459         }
460 }
461
462 function plugin_amazon_get_page($url)
463 {
464         $data = http_request($url);
465         return ($data['rc'] == 200) ? $data['data'] : '';
466 }
467
468 // is ASIN?
469 function is_asin()
470 {
471         global $asin, $asin_ext, $asin_all;
472
473         $tmpary = array();
474         if (preg_match('/^([A-Z0-9]{10}).?([0-9][0-9])?$/', $asin_all, $tmpary) == FALSE) {
475                 return FALSE;
476         } else {
477                 $asin     = $tmpary[1];
478                 $asin_ext = isset($tmpary[2]) ? $tmpary[2] : '';
479                 if ($asin_ext == '') $asin_ext = '09';
480                 $asin_all = $asin . $asin_ext;
481                 return TRUE;
482         }
483 }
484 ?>