xref: /plugin/amazonlight/syntax.php (revision 1c1d842e729f74d02e36e6f50a061ad4642316f6)
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        if ($param['price'] && $data['price']) {
144            echo '<div class="amazon_price">' . hsc($data['price']) . '</div>';
145        }
146        echo '</div>';
147
148        return ob_get_clean();
149    }
150
151    /**
152     * Fetch the meta data
153     *
154     * @param string $asin
155     * @param string $country
156     * @return array
157     * @throws Exception
158     */
159    protected function fetchData($asin, $country)
160    {
161        $partner = $this->getConf('partner_' . $country);
162        if (!$partner) $partner = 'none';
163        $region = self::REGIONS[$country];
164
165        $attr = [
166            'ServiceVersion' => '20070822',
167            'OneJS' => '1',
168            'Operation' => 'GetAdHtml',
169            'MarketPlace' => strtoupper($country),
170            'source' => 'ss',
171            'ref' => 'as_ss_li_til',
172            'ad_type' => 'product_link',
173            'tracking_id' => $partner,
174            'marketplace' => 'amazon',
175            'region' => strtoupper($country),
176            'placement' => '0670022411',
177            'asins' => $asin,
178            'show_border' => 'true',
179            'link_opens_in_new_window' => 'true',
180        ];
181        $url = 'http://' . $region . '.amazon-adsystem.com/widgets/q?' . buildURLparams($attr, '&');
182
183        $http = new DokuHTTPClient();
184        $html = $http->get($url);
185        if (!$html) {
186            throw new \Exception('Failed to fetch data. Status ' . $http->status);
187        }
188
189        $result = [];
190
191        if (preg_match('/class="price".*?>(.*?)<\/span>/s', $html, $m)) {
192            $result['price'] = $m[1];
193        }
194
195        if (preg_match('/<a .* id="titlehref" [^>]*?>([^<]*?)<\/a>/s', $html, $m)) {
196            $result['title'] = $m[1];
197        }
198
199        if (preg_match('/<a .* id="titlehref" href=(.*?) /s', $html, $m)) {
200            $result['url'] = trim($m[1], '\'"');
201        }
202
203        $result['img'] = $this->getImageURL($asin, $country);
204
205        return $result;
206    }
207
208    /**
209     * @param $asin
210     * @param $country
211     * @return string
212     */
213    protected function getImageURL($asin, $country)
214    {
215        $partner = $this->getConf('partner_' . $country);
216        if (!$partner) $partner = 'none';
217        $region = self::REGIONS[$country];
218
219        $attr = [
220            '_encoding' => 'UTF8',
221            'ASIN' => $asin,
222            'Format' => '_SL250_',
223            'ID' => 'AsinImage',
224            'MarketPlace' => strtoupper($country),
225            'ServiceVersion' => '20070822',
226            'WS' => '1',
227            'tag' => $partner,
228        ];
229        $url = 'http://' . $region . '.amazon-adsystem.com/widgets/q?' . buildURLparams($attr, '&');
230
231        return $url;
232    }
233
234}
235
236