9 * LICENSE: This source file is licensed under the terms of the GNU General Public License.
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
18 // Amazon plugin: Book-review maker via amazon.com/amazon.jp
21 // 2004-2005 PukiWiki Developers Team
22 // 2003 閑舎 <raku@rakunet.org> (Original author)
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 // インラインプラグインの呼び出し方を修正。
33 // 画像、タイトルのキャッシュによる速度の大幅アップ。
34 // * 0.7 ブックレビュー生成のデバッグ、認証問題の一応のクリア。
35 // * 0.8 amazon 全商品の画像を表示。
37 // * 0.9 RedHat9+php4.3.2+apache2.0.46 で画像が途中までしか読み込まれない問題に対処。
38 // 日本語ページの下にブックレビューを作ろうとすると文字化けして作れない問題の解決。
39 // 書籍でなく CD など、ASIN 部分が長くてもタイトルをうまく拾うようにする。
40 // 写影のみ取り込むのでなければ、B000002G6J.01 と書かず B000002G6J と書いても写影が出るようにする。
41 // ASIN に対応するキャッシュ画像/キャッシュタイトルをそれぞれ削除する機能追加。
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 をトライする、で暫定的に解決。
53 // * 著作権が関連する為、www.amazon.co.jp のアソシエイトプログラムを確認の上ご利用下さい。
54 // * レビューは、amazon プラグインが呼び出す編集画面はもう出来て PukiWiki に登録されているので、
55 // 中止するなら全文を削除してページの更新ボタンを押すこと。
56 // * 下の PLUGIN_AMAZON_AID、PROXY サーバの部分、expire の部分を適当に編集して使用してください(他はそのままでも Ok)。
58 // Thanks to: Reimy and PukiWiki Developers Team
61 /////////////////////////////////////////////////
64 // Amazon associate ID
65 //define('PLUGIN_AMAZON_AID',''); // None
66 define('PLUGIN_AMAZON_AID','');
68 // Expire caches per ? days
69 define('PLUGIN_AMAZON_EXPIRE_IMAGECACHE', 1);
70 define('PLUGIN_AMAZON_EXPIRE_TITLECACHE', 356);
72 // Alternative image for 'Image not found'
73 define('PLUGIN_AMAZON_NO_IMAGE', IMAGE_DIR . 'noimage.png');
79 define('PLUGIN_AMAZON_SHOP_URI', 'http://www.amazon.co.jp/exec/obidos/ASIN/');
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=');
87 define('PLUGIN_AMAZON_SHOP_URI', 'http://www.amazon.com/exec/obidos/ASIN/');
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=');
95 /////////////////////////////////////////////////
97 function plugin_amazon_init()
99 global $amazon_aid, $amazon_body;
101 if (PLUGIN_AMAZON_AID == '') {
104 $amazon_aid = PLUGIN_AMAZON_AID . '/';
106 $amazon_body = <<<EOD
117 // まず、このレビューを止める場合、全文を削除し、ページの[更新ボタン]を押してください!(PukiWiki にはもう登録されています)
118 // 続けるなら、上の、[[ここ編集のこと]]部分を括弧を含めて削除し、書き直してください。
119 // お名前、部分はご自分の名前に変更してください。私だと、閑舎、です。
120 // **お薦め対象、より上は、新しい行を追加しないでください。目次作成に使用するので。
121 // //で始まるコメント行は、最終的に全部カットしてください。目次が正常に作成できない可能性があります。
126 function plugin_amazon_convert()
128 //global $script, $vars, $asin, $asin_all;
129 global $asin, $asin_all;
131 if (func_num_args() > 3) {
132 if (PKWK_READONLY) return ''; // Show nothing
134 return '#amazon([ASIN-number][,left|,right]' .
135 '[,book-title|,image|,delimage|,deltitle|,delete])';
137 } else if (func_num_args() == 0) {
139 if (PKWK_READONLY) return ''; // Show nothing
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('?');
147 <form action="$script" method="post" class="form">
149 <input type="hidden" name="plugin" value="amazon" />
150 <input type="hidden" name="refer" value="$s_page" />
152 <input type="text" name="asin" size="30" value="" />
153 <input type="submit" class="button" value="レビュー編集" /> (ISBN 10 桁 or ASIN 12 桁)
160 $aryargs = func_get_args();
162 $align = strtolower($aryargs[1]);
163 if ($align == 'clear') return '<div style="clear:both"></div>'; // 改行挿入
164 if ($align != 'left') $align = 'right'; // 配置決定
166 $asin_all = htmlspecialchars($aryargs[0]); // for XSS
167 if (is_asin() == FALSE && $align != 'clear') return FALSE;
169 if ($aryargs[2] != '') {
171 $title = $alt = htmlspecialchars($aryargs[2]); // for XSS
172 if ($alt == 'image') {
173 $alt = plugin_amazon_get_asin_title();
174 if ($alt == '') return FALSE;
176 } else if ($alt == 'delimage') {
177 if (unlink(CACHE_DIR . 'ASIN' . $asin . '.jpg')) {
178 return 'Image of ' . $asin . ' deleted...';
180 return 'Image of ' . $asin . ' NOT DELETED...';
182 } elseif ($alt == 'deltitle') {
183 if (unlink(CACHE_DIR . 'ASIN' . $asin . '.tit')) {
184 return 'Title of ' . $asin . ' deleted...';
186 return 'Title of ' . $asin . ' NOT DELETED...';
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...';
193 return 'Title and Image of ' . $asin . ' NOT DELETED...';
198 $alt = $title = plugin_amazon_get_asin_title();
199 if ($alt == '') return FALSE;
202 return plugin_amazon_print_object($align, $alt, $title);
205 function plugin_amazon_action()
207 //global $vars, $script, $edit_auth, $edit_auth_users;
208 global $edit_auth, $edit_auth_users;
209 global $amazon_body, $asin, $asin_all;
211 if (PKWK_READONLY) die_message('PKWK_READONLY prohibits editing');
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')))) : '';
219 $retvars['msg'] = 'ブックレビュー編集';
220 $retvars['refer'] = $s_page;
221 $retvars['body'] = plugin_amazon_convert();
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'] : '';
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));
236 $title = plugin_amazon_get_asin_title();
237 if ($title == '' || preg_match('#^/#', $s_page)) {
239 //header('Location: ' . get_script_uri() . '?' . rawurlencode($s_page));
240 header('Location: ' . get_script_uri() . WikiParam::convQuery('?' . rawurlencode($s_page), false));
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));
253 function plugin_amazon_inline()
255 global $amazon_aid, $asin, $asin_all;
257 list($asin_all) = func_get_args();
259 $asin_all = htmlspecialchars($asin_all); // for XSS
260 if (! is_asin()) return FALSE;
262 $title = plugin_amazon_get_asin_title();
266 return '<a href="' . PLUGIN_AMAZON_SHOP_URI .
267 $asin . '/' . $amazon_aid . 'ref=nosim">' . $title . '</a>' . "\n";
271 function plugin_amazon_print_object($align, $alt, $title)
274 global $asin, $asin_ext, $asin_all;
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';
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";
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";
299 function plugin_amazon_get_asin_title()
301 global $asin, $asin_ext, $asin_all;
303 if ($asin_all == '') return '';
305 $nocache = $nocachable = 0;
307 $url = PLUGIN_AMAZON_XML . $asin;
309 if (file_exists(CACHE_DIR) === FALSE || is_writable(CACHE_DIR) === FALSE) $nocachable = 1; // キャッシュ不可の場合
311 if (($title = plugin_amazon_cache_title_fetch(CACHE_DIR)) == FALSE) {
312 $nocache = 1; // キャッシュ見つからず
313 $body = plugin_amazon_get_page($url); // しかたないので取りにいく
315 $body = mb_convert_encoding($body, SOURCE_ENCODING, 'UTF-8');
316 preg_match('/<ProductName>([^<]*)</', $body, $tmpary);
317 $title = trim($tmpary[1]);
319 // preg_match('#<ImageUrlMedium>http://images-jp.amazon.com/images/P/[^.]+\.(..)\.#',
321 // if ($tmpary[1] != '') {
322 // $asin_ext = $tmpary[1];
323 // $asin_all = $asin . $asin_ext;
330 if ($nocache == 1 && $nocachable != 1)
331 plugin_amazon_cache_title_save($title, CACHE_DIR);
337 function plugin_amazon_cache_title_fetch($dir)
339 global $asin, $asin_ext, $asin_all;
341 $filename = $dir . 'ASIN' . $asin . '.tit';
344 if (! is_readable($filename)) {
346 } elseif (PLUGIN_AMAZON_EXPIRE_TITLECACHE * 3600 * 24 < time() - filemtime($filename)) {
350 if ($get_tit) return FALSE;
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;
358 if (strlen($title) > 0) {
366 function plugin_amazon_cache_image_fetch($dir)
368 global $asin, $asin_ext, $asin_all;
370 $filename = $dir . 'ASIN' . $asin . '.jpg';
373 if (! is_readable($filename)) {
375 } elseif (PLUGIN_AMAZON_EXPIRE_IMAGECACHE * 3600 * 24 < time() - filemtime($filename)) {
380 $url = 'http://images-jp.amazon.com/images/P/' . $asin . '.' . $asin_ext . '.MZZZZZZZ.jpg';
381 if (! is_url($url)) return FALSE;
383 $body = plugin_amazon_get_page($url);
385 $tmpfile = $dir . 'ASIN' . $asin . '.jpg.0';
386 $fp = fopen($tmpfile, 'wb');
389 $size = getimagesize($tmpfile);
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);
398 $tmpfile = $dir . 'ASIN' . $asin . '.jpg.0';
399 $fp = fopen($tmpfile, 'wb');
402 $size = getimagesize($tmpfile);
406 if ($body == '' || $size[1] <= 1) {
407 $fp = fopen(PLUGIN_AMAZON_NO_IMAGE, 'rb');
408 if (! $fp) return FALSE;
411 while (! feof($fp)) $body .= fread($fp, 4096);
415 plugin_amazon_cache_image_save($body, CACHE_DIR);
421 function plugin_amazon_cache_title_save($data, $dir)
423 global $asin, $asin_ext, $asin_all;
425 $filename = $dir . 'ASIN' . $asin . '.tit';
426 $fp = fopen($filename, 'w');
434 function plugin_amazon_cache_image_save($data, $dir)
436 global $asin, $asin_ext, $asin_all;
438 $filename = $dir . 'ASIN' . $asin . '.jpg';
439 $fp = fopen($filename, 'wb');
447 function plugin_amazon_review_save($page, $data)
449 global $asin, $asin_ext, $asin_all;
451 $filename = DATA_DIR . encode($page) . '.txt';
452 if (! is_readable($filename)) {
453 $fp = fopen($filename, 'w');
462 function plugin_amazon_get_page($url)
464 $data = http_request($url);
465 return ($data['rc'] == 200) ? $data['data'] : '';
471 global $asin, $asin_ext, $asin_all;
474 if (preg_match('/^([A-Z0-9]{10}).?([0-9][0-9])?$/', $asin_all, $tmpary) == FALSE) {
478 $asin_ext = isset($tmpary[2]) ? $tmpary[2] : '';
479 if ($asin_ext == '') $asin_ext = '09';
480 $asin_all = $asin . $asin_ext;