OSDN Git Service

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