1<?php 2/** 3 * DokuWiki Plugin amazonlight (Syntax Component) 4 * 5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6 * @author Andreas Gohr <andi@splitbrain.org> 7 */ 8 9// must be run within Dokuwiki 10if (!defined('DOKU_INC')) { 11 die(); 12} 13 14class syntax_plugin_amazonlight extends DokuWiki_Syntax_Plugin 15{ 16 17 /** @var array what regions to use for the different countries */ 18 const REGIONS = [ 19 'us' => 'ws-na', 20 'ca' => 'ws-na', 21 'de' => 'ws-eu', 22 'gb' => 'ws-eu', 23 'fr' => 'ws-eu', 24 'jp' => 'ws-fe', 25 ]; 26 27 /** @inheritDoc */ 28 public function getType() 29 { 30 return 'substition'; 31 } 32 33 /** @inheritDoc */ 34 public function getPType() 35 { 36 return 'block'; 37 } 38 39 /** @inheritDoc */ 40 public function getSort() 41 { 42 return 160; 43 } 44 45 /** 46 * Connect lookup pattern to lexer. 47 * 48 * @param string $mode Parser mode 49 */ 50 public function connectTo($mode) 51 { 52 $this->Lexer->addSpecialPattern('\{\{amazon>[\w:\\- =]+\}\}', $mode, 'plugin_amazonlight'); 53 } 54 55 /** @inheritDoc */ 56 public function handle($match, $state, $pos, Doku_Handler $handler) 57 { 58 $match = substr($match, 9, -2); 59 list($ctry, $asin) = explode(':', $match, 2); 60 61 // no country given? 62 if (empty($asin)) { 63 $asin = $ctry; 64 $ctry = 'us'; 65 } 66 67 // default parameters... 68 $params = array( 69 'imgw' => $this->getConf('imgw'), 70 'imgh' => $this->getConf('imgh'), 71 'price' => $this->getConf('showprice'), 72 ); 73 // ...can be overridden 74 list($asin, $more) = explode(' ', $asin, 2); 75 $params['asin'] = $asin; 76 77 if (preg_match('/(\d+)x(\d+)/i', $more, $match)) { 78 $params['imgw'] = $match[1]; 79 $params['imgh'] = $match[2]; 80 } 81 if (preg_match('/noprice/i', $more, $match)) { 82 $params['price'] = false; 83 } elseif (preg_match('/(show)?price/i', $more, $match)) { 84 $params['price'] = true; 85 } 86 87 // correct country given? 88 if ($ctry === 'uk') $ctry = 'gb'; 89 if (!preg_match('/^(us|gb|jp|de|fr|ca)$/', $ctry)) { 90 $ctry = 'us'; 91 } 92 $params['country'] = $ctry; 93 94 return $params; 95 } 96 97 /** @inheritDoc */ 98 public function render($mode, Doku_Renderer $renderer, $data) 99 { 100 if ($mode !== 'xhtml') { 101 return false; 102 } 103 104 $html = $this->output($data); 105 if (!$html) { 106 if ($data['country'] == 'de') { 107 $renderer->interwikilink('Amazon', 'Amazon.de', 'amazon.de', $data['asin']); 108 } else { 109 $renderer->interwikilink('Amazon', 'Amazon', 'amazon', $data['asin']); 110 } 111 } 112 113 $renderer->doc .= $html; 114 115 return true; 116 } 117 118 /** 119 * @param array $param 120 * @return string 121 */ 122 protected function output($param) 123 { 124 global $conf; 125 126 try { 127 $data = $this->fetchData($param['asin'], $param['country']); 128 } catch (\Exception $e) { 129 msg(hsc($e->getMessage()), -1); 130 return false; 131 } 132 133 $img = ml($data['img'], array('w' => $param['imgw'], 'h' => $param['imgh'])); 134 135 ob_start(); 136 echo '<div class="amazon">'; 137 echo '<a href="' . $data['url'] . '"'; 138 if ($conf['target']['extern']) echo ' target="' . $conf['target']['extern'] . '"'; 139 echo '>'; 140 echo '<img src="' . $img . '" width="' . $param['imgw'] . '" height="' . $param['imgh'] . '" alt="" />'; 141 echo '</a>'; 142 143 echo '<div class="amazon_title">'; 144 echo '<a href="' . $data['url'] . '"'; 145 if ($conf['target']['extern']) echo ' target="' . $conf['target']['extern'] . '"'; 146 echo '>'; 147 echo hsc($data['title']); 148 echo '</a>'; 149 echo '</div>'; 150 151 echo '<div class="amazon_isbn">'; 152 echo hsc($data['isbn']); 153 echo '</div>'; 154 155 if ($param['price'] && $data['price']) { 156 echo '<div class="amazon_price">' . hsc($data['price']) . '</div>'; 157 } 158 echo '</div>'; 159 160 return ob_get_clean(); 161 } 162 163 /** 164 * Fetch the meta data 165 * 166 * @param string $asin 167 * @param string $country 168 * @return array 169 * @throws Exception 170 */ 171 protected function fetchData($asin, $country) 172 { 173 $partner = $this->getConf('partner_' . $country); 174 if (!$partner) $partner = 'none'; 175 $region = self::REGIONS[$country]; 176 177 $attr = [ 178 'ServiceVersion' => '20070822', 179 'OneJS' => '1', 180 'Operation' => 'GetAdHtml', 181 'MarketPlace' => strtoupper($country), 182 'source' => 'ss', 183 'ref' => 'as_ss_li_til', 184 'ad_type' => 'product_link', 185 'tracking_id' => $partner, 186 'marketplace' => 'amazon', 187 'region' => strtoupper($country), 188 'placement' => '0670022411', 189 'asins' => $asin, 190 'show_border' => 'true', 191 'link_opens_in_new_window' => 'true', 192 ]; 193 $url = 'http://' . $region . '.amazon-adsystem.com/widgets/q?' . buildURLparams($attr, '&'); 194 195 $http = new DokuHTTPClient(); 196 $html = $http->get($url); 197 if (!$html) { 198 throw new \Exception('Failed to fetch data. Status ' . $http->status); 199 } 200 201 $result = []; 202 203 if (preg_match('/class="price".*?>(.*?)<\/span>/s', $html, $m)) { 204 $result['price'] = $m[1]; 205 } 206 207 if (preg_match('/<a .* id="titlehref" [^>]*?>([^<]*?)<\/a>/s', $html, $m)) { 208 $result['title'] = $m[1]; 209 } else { 210 throw new \Exception('Could not find title in data'); 211 } 212 213 if (preg_match('/<a .* id="titlehref" href=(.*?) /s', $html, $m)) { 214 $result['url'] = trim($m[1], '\'"'); 215 } else { 216 throw new \Exception('Could not find url in data'); 217 } 218 219 if (preg_match('/^\d{10,13}$/', $asin)) { 220 $result['isbn'] = 'ISBN ' . $asin; 221 } 222 223 $result['img'] = $this->getImageURL($asin, $country); 224 225 return $result; 226 } 227 228 /** 229 * @param $asin 230 * @param $country 231 * @return string 232 */ 233 protected function getImageURL($asin, $country) 234 { 235 $partner = $this->getConf('partner_' . $country); 236 if (!$partner) $partner = 'none'; 237 $region = self::REGIONS[$country]; 238 239 $attr = [ 240 '_encoding' => 'UTF8', 241 'ASIN' => $asin, 242 'Format' => '_SL250_', 243 'ID' => 'AsinImage', 244 'MarketPlace' => strtoupper($country), 245 'ServiceVersion' => '20070822', 246 'WS' => '1', 247 'tag' => $partner, 248 ]; 249 $url = 'https://' . $region . '.amazon-adsystem.com/widgets/q?' . buildURLparams($attr, '&'); 250 251 return $url; 252 } 253 254} 255 256