1<?php
2
3// This file is part of Moodle - http://moodle.org/
4//
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17
18/**
19 * wikimedia class
20 * class for communication with Wikimedia Commons API
21 *
22 * @author Dongsheng Cai <dongsheng@moodle.com>, Raul Kern <raunator@gmail.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
24 */
25
26define('WIKIMEDIA_THUMBS_PER_PAGE', 24);
27define('WIKIMEDIA_FILE_NS', 6);
28define('WIKIMEDIA_IMAGE_SIDE_LENGTH', 1024);
29define('WIKIMEDIA_THUMB_SIZE', 120);
30
31class wikimedia {
32    private $_conn  = null;
33    private $_param = array();
34
35    public function __construct($url = '') {
36        if (empty($url)) {
37            $this->api = 'https://commons.wikimedia.org/w/api.php';
38        } else {
39            $this->api = $url;
40        }
41        $this->_param['format'] = 'php';
42        $this->_param['redirects'] = true;
43        $this->_conn = new curl(array('cache'=>true, 'debug'=>false));
44    }
45    public function login($user, $pass) {
46        $this->_param['action']   = 'login';
47        $this->_param['lgname']   = $user;
48        $this->_param['lgpassword'] = $pass;
49        $content = $this->_conn->post($this->api, $this->_param);
50        $result = unserialize($content);
51        if (!empty($result['result']['sessionid'])) {
52            $this->userid = $result['result']['lguserid'];
53            $this->username = $result['result']['lgusername'];
54            $this->token = $result['result']['lgtoken'];
55            return true;
56        } else {
57            return false;
58        }
59    }
60    public function logout() {
61        $this->_param['action']   = 'logout';
62        $content = $this->_conn->post($this->api, $this->_param);
63        return;
64    }
65    public function get_image_url($titles) {
66        $image_urls = array();
67        $this->_param['action'] = 'query';
68        if (is_array($titles)) {
69            foreach ($titles as $title) {
70                $this->_param['titles'] .= ('|'.urldecode($title));
71            }
72        } else {
73            $this->_param['titles'] = urldecode($titles);
74        }
75        $this->_param['prop']   = 'imageinfo';
76        $this->_param['iiprop'] = 'url';
77        $content = $this->_conn->post($this->api, $this->_param);
78        $result = unserialize($content);
79        foreach ($result['query']['pages'] as $page) {
80            if (!empty($page['imageinfo'][0]['url'])) {
81                $image_urls[] = $page['imageinfo'][0]['url'];
82            }
83        }
84        return $image_urls;
85    }
86    public function get_images_by_page($title) {
87        $image_urls = array();
88        $this->_param['action'] = 'query';
89        $this->_param['generator'] = 'images';
90        $this->_param['titles'] = urldecode($title);
91        $this->_param['prop']   = 'images|info|imageinfo';
92        $this->_param['iiprop'] = 'url';
93        $content = $this->_conn->post($this->api, $this->_param);
94        $result = unserialize($content);
95        if (!empty($result['query']['pages'])) {
96            foreach ($result['query']['pages'] as $page) {
97                $image_urls[$page['title']] = $page['imageinfo'][0]['url'];
98            }
99        }
100        return $image_urls;
101    }
102    /**
103     * Generate thumbnail URL from image URL.
104     *
105     * @param string $image_url
106     * @param int $orig_width
107     * @param int $orig_height
108     * @param int $thumb_width
109     * @param bool $force When true, forces the generation of a thumb URL.
110     * @global object OUTPUT
111     * @return string
112     */
113    public function get_thumb_url($image_url, $orig_width, $orig_height, $thumb_width = 75, $force = false) {
114        global $OUTPUT;
115
116        if (!$force && $orig_width <= $thumb_width && $orig_height <= $thumb_width) {
117            return $image_url;
118        } else {
119            $thumb_url = '';
120            $commons_main_dir = 'https://upload.wikimedia.org/wikipedia/commons/';
121            if ($image_url) {
122                $short_path = str_replace($commons_main_dir, '', $image_url);
123                $extension = strtolower(pathinfo($short_path, PATHINFO_EXTENSION));
124                if (strcmp($extension, 'gif') == 0) {  //no thumb for gifs
125                    return $OUTPUT->image_url(file_extension_icon('.gif', $thumb_width))->out(false);
126                }
127                $dir_parts = explode('/', $short_path);
128                $file_name = end($dir_parts);
129                if ($orig_height > $orig_width) {
130                    $thumb_width = round($thumb_width * $orig_width/$orig_height);
131                }
132                $thumb_url = $commons_main_dir . 'thumb/' . implode('/', $dir_parts) . '/'. $thumb_width .'px-' . $file_name;
133                if (strcmp($extension, 'svg') == 0) {  //png thumb for svg-s
134                    $thumb_url .= '.png';
135                }
136            }
137            return $thumb_url;
138        }
139    }
140
141    /**
142     * Search for images and return photos array.
143     *
144     * @param string $keyword
145     * @param int $page
146     * @param array $params additional query params
147     * @return array
148     */
149    public function search_images($keyword, $page = 0, $params = array()) {
150        global $OUTPUT;
151        $files_array = array();
152        $this->_param['action'] = 'query';
153        $this->_param['generator'] = 'search';
154        $this->_param['gsrsearch'] = $keyword;
155        $this->_param['gsrnamespace'] = WIKIMEDIA_FILE_NS;
156        $this->_param['gsrlimit'] = WIKIMEDIA_THUMBS_PER_PAGE;
157        $this->_param['gsroffset'] = $page * WIKIMEDIA_THUMBS_PER_PAGE;
158        $this->_param['prop']   = 'imageinfo';
159        $this->_param['iiprop'] = 'url|dimensions|mime|timestamp|size|user';
160        $this->_param += $params;
161        $this->_param += array('iiurlwidth' => WIKIMEDIA_IMAGE_SIDE_LENGTH,
162            'iiurlheight' => WIKIMEDIA_IMAGE_SIDE_LENGTH);
163        //didn't work with POST
164        $content = $this->_conn->get($this->api, $this->_param);
165        $result = unserialize($content);
166        if (!empty($result['query']['pages'])) {
167            foreach ($result['query']['pages'] as $page) {
168                $title = $page['title'];
169                $file_type = $page['imageinfo'][0]['mime'];
170                $image_types = array('image/jpeg', 'image/png', 'image/gif', 'image/svg+xml');
171                if (in_array($file_type, $image_types)) {  //is image
172                    $extension = pathinfo($title, PATHINFO_EXTENSION);
173                    $issvg = strcmp($extension, 'svg') == 0;
174
175                    // Get PNG equivalent to SVG files.
176                    if ($issvg) {
177                        $title .= '.png';
178                    }
179
180                    // The thumbnail (max size requested) is smaller than the original size, we will use the thumbnail.
181                    if ($page['imageinfo'][0]['thumbwidth'] < $page['imageinfo'][0]['width']) {
182                        $attrs = array(
183                            //upload scaled down image
184                            'source' => $page['imageinfo'][0]['thumburl'],
185                            'image_width' => $page['imageinfo'][0]['thumbwidth'],
186                            'image_height' => $page['imageinfo'][0]['thumbheight']
187                        );
188                        if ($attrs['image_width'] <= WIKIMEDIA_THUMB_SIZE && $attrs['image_height'] <= WIKIMEDIA_THUMB_SIZE) {
189                            $attrs['realthumbnail'] = $attrs['source'];
190                        }
191                        if ($attrs['image_width'] <= 24 && $attrs['image_height'] <= 24) {
192                            $attrs['realicon'] = $attrs['source'];
193                        }
194
195                    // We use the original file.
196                    } else {
197                        $attrs = array(
198                            //upload full size image
199                            'image_width' => $page['imageinfo'][0]['width'],
200                            'image_height' => $page['imageinfo'][0]['height'],
201                            'size' => $page['imageinfo'][0]['size']
202                        );
203
204                        // We cannot use the source when the file is SVG.
205                        if ($issvg) {
206                            // So we generate a PNG thumbnail of the file at its original size.
207                            $attrs['source'] = $this->get_thumb_url($page['imageinfo'][0]['url'], $page['imageinfo'][0]['width'],
208                                $page['imageinfo'][0]['height'], $page['imageinfo'][0]['width'], true);
209                        } else {
210                            $attrs['source'] = $page['imageinfo'][0]['url'];
211                        }
212                    }
213                    $attrs += array(
214                        'realthumbnail' => $this->get_thumb_url($page['imageinfo'][0]['url'], $page['imageinfo'][0]['width'], $page['imageinfo'][0]['height'], WIKIMEDIA_THUMB_SIZE),
215                        'realicon' => $this->get_thumb_url($page['imageinfo'][0]['url'], $page['imageinfo'][0]['width'], $page['imageinfo'][0]['height'], 24),
216                        'author' => $page['imageinfo'][0]['user'],
217                        'datemodified' => strtotime($page['imageinfo'][0]['timestamp']),
218                        );
219                } else {  // other file types
220                    $attrs = array('source' => $page['imageinfo'][0]['url']);
221                }
222                $files_array[] = array(
223                    'title'=>substr($title, 5),         //chop off 'File:'
224                    'thumbnail' => $OUTPUT->image_url(file_extension_icon(substr($title, 5), WIKIMEDIA_THUMB_SIZE))->out(false),
225                    'thumbnail_width' => WIKIMEDIA_THUMB_SIZE,
226                    'thumbnail_height' => WIKIMEDIA_THUMB_SIZE,
227                    'license' => 'cc-sa',
228                    // the accessible url of the file
229                    'url'=>$page['imageinfo'][0]['descriptionurl']
230                ) + $attrs;
231            }
232        }
233        return $files_array;
234    }
235
236}
237