xref: /plugin/amazonlight/syntax.php (revision e20d6e78d70fbd01efc177563844e14e25061e16)
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        $renderer->doc .= $html;
106
107        return true;
108    }
109
110    /**
111     * @param array $param
112     * @return string
113     */
114    protected function output($param)
115    {
116        global $conf;
117
118        try {
119            $data = $this->fetchData($param['asin'], $param['country']);
120        } catch (\Exception $e) {
121            msg(hsc($e->getMessage()), -1);
122            return false;
123        }
124
125        $img = ml($data['img'], array('w' => $param['imgw'], 'h' => $param['imgh']));
126
127        ob_start();
128        echo '<div class="amazon">';
129        echo '<a href="' . $data['url'] . '"';
130        if ($conf['target']['extern']) echo ' target="' . $conf['target']['extern'] . '"';
131        echo '>';
132        echo '<img src="' . $img . '" width="' . $param['imgw'] . '" height="' . $param['imgh'] . '" alt="" />';
133        echo '</a>';
134
135        echo '<div class="amazon_title">';
136        echo '<a href="' . $data['url'] . '"';
137        if ($conf['target']['extern']) echo ' target="' . $conf['target']['extern'] . '"';
138        echo '>';
139        echo hsc($data['title']);
140        echo '</a>';
141        echo '</div>';
142
143        echo '<div class="amazon_isbn">';
144        echo hsc($data['isbn']);
145        echo '</div>';
146
147        if ($param['price'] && $data['price']) {
148            echo '<div class="amazon_price">' . hsc($data['price']) . '</div>';
149        }
150        echo '</div>';
151
152        return ob_get_clean();
153    }
154
155    /**
156     * Fetch the meta data
157     *
158     * @param string $asin
159     * @param string $country
160     * @return array
161     * @throws Exception
162     */
163    protected function fetchData($asin, $country)
164    {
165        $partner = $this->getConf('partner_' . $country);
166        if (!$partner) $partner = 'none';
167        $region = self::REGIONS[$country];
168
169        $attr = [
170            'ServiceVersion' => '20070822',
171            'OneJS' => '1',
172            'Operation' => 'GetAdHtml',
173            'MarketPlace' => strtoupper($country),
174            'source' => 'ss',
175            'ref' => 'as_ss_li_til',
176            'ad_type' => 'product_link',
177            'tracking_id' => $partner,
178            'marketplace' => 'amazon',
179            'region' => strtoupper($country),
180            'placement' => '0670022411',
181            'asins' => $asin,
182            'show_border' => 'true',
183            'link_opens_in_new_window' => 'true',
184        ];
185        $url = 'http://' . $region . '.amazon-adsystem.com/widgets/q?' . buildURLparams($attr, '&');
186
187        $http = new DokuHTTPClient();
188        $html = $http->get($url);
189        if (!$html) {
190            throw new \Exception('Failed to fetch data. Status ' . $http->status);
191        }
192
193        $result = [];
194
195        if (preg_match('/class="price".*?>(.*?)<\/span>/s', $html, $m)) {
196            $result['price'] = $m[1];
197        }
198
199        if (preg_match('/<a .* id="titlehref" [^>]*?>([^<]*?)<\/a>/s', $html, $m)) {
200            $result['title'] = $m[1];
201        }
202
203        if (preg_match('/<a .* id="titlehref" href=(.*?) /s', $html, $m)) {
204            $result['url'] = trim($m[1], '\'"');
205        }
206
207        if (preg_match('/^\d{10}$/', $asin)) {
208            $result['isbn'] = 'ISBN ' . $asin;
209        }
210
211        $result['img'] = $this->getImageURL($asin, $country);
212
213        return $result;
214    }
215
216    /**
217     * @param $asin
218     * @param $country
219     * @return string
220     */
221    protected function getImageURL($asin, $country)
222    {
223        $partner = $this->getConf('partner_' . $country);
224        if (!$partner) $partner = 'none';
225        $region = self::REGIONS[$country];
226
227        $attr = [
228            '_encoding' => 'UTF8',
229            'ASIN' => $asin,
230            'Format' => '_SL250_',
231            'ID' => 'AsinImage',
232            'MarketPlace' => strtoupper($country),
233            'ServiceVersion' => '20070822',
234            'WS' => '1',
235            'tag' => $partner,
236        ];
237        $url = 'http://' . $region . '.amazon-adsystem.com/widgets/q?' . buildURLparams($attr, '&');
238
239        return $url;
240    }
241
242}
243
244