/** * modified image request with invalid token * expect: 412 status code */ function test_invalid_token() { $invalid_tokens = array('invalid_token_wrongid' => media_get_token('junk', 200, 100), 'invalid_token_wrongh' => media_get_token($this->media, 200, 10), 'invalid_token_wrongw' => media_get_token($this->media, 20, 100), 'invalid_token_wrongwh' => media_get_token($this->media, 20, 10)); foreach ($invalid_tokens as $invalid_token) { $this->assertEquals(412, $this->fetchResponse('tok=' . $invalid_token . '&')->getStatusCode()); } }
/** * native image request which doesn't require a token * try: with a token & without a token * expect: (for both) header with mime-type, content matching source image filesize & no error response */ function test_no_token_required() { $this->width = $this->height = 0; // no width & height, means image request at native dimensions $any_token = 'tok=' . media_get_token('junk', 200, 100) . '&'; $no_token = ''; $bytes = filesize(mediaFN($this->media)); foreach (array($any_token, $no_token) as $token) { $response = $this->fetchResponse($token); $this->assertTrue((bool) $response->getHeader('Content-Type')); $this->assertEquals(strlen($response->getContent()), $bytes); $status_code = $response->getStatusCode(); $this->assertTrue(is_null($status_code) || 200 == $status_code); } }
function test_ml_imgresize_array_external() { global $conf; $conf['useslash'] = 0; $conf['userewrite'] = 0; $ids = array('https://example.com/lib/tpl/dokuwiki/images/logo.png', 'http://example.com/lib/tpl/dokuwiki/images/logo.png', 'ftp://example.com/lib/tpl/dokuwiki/images/logo.png'); $w = 80; $args = array('w' => $w); foreach ($ids as $id) { $tok = media_get_token($id, $w, 0); $hash = substr(PassHash::hmac('md5', $id, auth_cookiesalt()), 0, 6); $expect = DOKU_BASE . $this->script . '?w=' . $w . '&tok=' . $tok . '&media=' . rawurlencode($id); $this->assertEquals($expect, ml($id, $args)); } $h = 50; $args = array('h' => $h); $tok = media_get_token($id, $h, 0); $expect = DOKU_BASE . $this->script . '?h=' . $h . '&tok=' . $tok . '&media=' . rawurlencode($id); $this->assertEquals($expect, ml($id, $args)); $w = 80; $h = 50; $args = array('w' => $w, 'h' => $h); $tok = media_get_token($id, $w, $h); $expect = DOKU_BASE . $this->script . '?w=' . $w . '&h=' . $h . '&tok=' . $tok . '&media=' . rawurlencode($id); $this->assertEquals($expect, ml($id, $args)); }
/** * Build a link to a media file * * Will return a link to the detail page if $direct is false * * The $more parameter should always be given as array, the function then * will strip default parameters to produce even cleaner URLs * * @param string $id the media file id or URL * @param mixed $more string or array with additional parameters * @param bool $direct link to detail page if false * @param string $sep URL parameter separator * @param bool $abs Create an absolute URL * @return string */ function ml($id = '', $more = '', $direct = true, $sep = '&', $abs = false) { global $conf; $isexternalimage = media_isexternal($id); if (!$isexternalimage) { $id = cleanID($id); } if (is_array($more)) { // add token for resized images if (!empty($more['w']) || !empty($more['h']) || $isexternalimage) { $more['tok'] = media_get_token($id, $more['w'], $more['h']); } // strip defaults for shorter URLs if (isset($more['cache']) && $more['cache'] == 'cache') { unset($more['cache']); } if (empty($more['w'])) { unset($more['w']); } if (empty($more['h'])) { unset($more['h']); } if (isset($more['id']) && $direct) { unset($more['id']); } if (isset($more['rev']) && !$more['rev']) { unset($more['rev']); } $more = buildURLparams($more, $sep); } else { $matches = array(); if (preg_match_all('/\\b(w|h)=(\\d*)\\b/', $more, $matches, PREG_SET_ORDER) || $isexternalimage) { $resize = array('w' => 0, 'h' => 0); foreach ($matches as $match) { $resize[$match[1]] = $match[2]; } $more .= $more === '' ? '' : $sep; $more .= 'tok=' . media_get_token($id, $resize['w'], $resize['h']); } $more = str_replace('cache=cache', '', $more); //skip default $more = str_replace(',,', ',', $more); $more = str_replace(',', $sep, $more); } if ($abs) { $xlink = DOKU_URL; } else { $xlink = DOKU_BASE; } // external URLs are always direct without rewriting if ($isexternalimage) { $xlink .= 'lib/exe/fetch.php'; $xlink .= '?' . $more; $xlink .= $sep . 'media=' . rawurlencode($id); return $xlink; } $id = idfilter($id); // decide on scriptname if ($direct) { if ($conf['userewrite'] == 1) { $script = '_media'; } else { $script = 'lib/exe/fetch.php'; } } else { if ($conf['userewrite'] == 1) { $script = '_detail'; } else { $script = 'lib/exe/detail.php'; } } // build URL based on rewrite mode if ($conf['userewrite']) { $xlink .= $script . '/' . $id; if ($more) { $xlink .= '?' . $more; } } else { if ($more) { $xlink .= $script . '?' . $more; $xlink .= $sep . 'media=' . $id; } else { $xlink .= $script . '?media=' . $id; } } return $xlink; }
/** * Check for media for preconditions and return correct status code * * READ: MEDIA, MIME, EXT, CACHE * WRITE: MEDIA, FILE, array( STATUS, STATUSMESSAGE ) * * @author Gerry Weissbach <*****@*****.**> * * @param string $media reference to the media id * @param string $file reference to the file variable * @param string $rev * @param int $width * @param int $height * @return array as array(STATUS, STATUSMESSAGE) */ function checkFileStatus(&$media, &$file, $rev = '', $width = 0, $height = 0) { global $MIME, $EXT, $CACHE, $INPUT; //media to local file if (media_isexternal($media)) { //check token for external image and additional for resized and cached images if (media_get_token($media, $width, $height) !== $INPUT->str('tok')) { return array(412, 'Precondition Failed'); } //handle external images if (strncmp($MIME, 'image/', 6) == 0) { $file = media_get_from_URL($media, $EXT, $CACHE); } if (!$file) { //download failed - redirect to original URL return array(302, $media); } } else { $media = cleanID($media); if (empty($media)) { return array(400, 'Bad request'); } // check token for resized images if (($width || $height) && media_get_token($media, $width, $height) !== $INPUT->str('tok')) { return array(412, 'Precondition Failed'); } //check permissions (namespace only) if (auth_quickaclcheck(getNS($media) . ':X') < AUTH_READ) { return array(403, 'Forbidden'); } $file = mediaFN($media, $rev); } //check file existance if (!file_exists($file)) { return array(404, 'Not Found'); } return array(200, null); }
/** * Renders internal and external media with exif info at bottom of each JPEG image * * @author Andreas Gohr <*****@*****.**> * @param string $src media ID * @param string $title descriptive text * @param string $align left|center|right * @param int $width width of media in pixel * @param int $height height of media in pixel * @param string $cache cache|recache|nocache * @param bool $render should the media be embedded inline or just linked * @return string */ function _media($src, $title = null, $align = null, $width = null, $height = null, $cache = null, $render = true) { $ret = ''; list($ext, $mime) = mimetype($src); if (substr($mime, 0, 5) == 'image') { // first get the $title if (!is_null($title)) { $title = $this->_xmlEntities($title); } elseif ($ext == 'jpg' || $ext == 'jpeg') { //try to use the caption from IPTC/EXIF require_once DOKU_INC . 'lib/plugins/colorbox/JpegMetaGPS.php'; $jpeg = new JpegMetaGPS(mediaFN($src)); if ($jpeg !== false) { $cap = $jpeg->getTitle(); } if (!empty($cap)) { $title = $this->_xmlEntities($cap); } } if (!$render) { // if the picture is not supposed to be rendered // return the title of the picture if (!$title) { // just show the sourcename $title = $this->_xmlEntities(utf8_basename(noNS($src))); } return $title; } //add image tag if (($ext == 'jpg' || $ext == 'jpeg') && !$width && !strpos($src, 'wiki:dokuwiki')) { // force to scale image to 680px $ret .= '<img src="' . ml($src, array('w' => "680", 'h' => $height, 'cache' => $cache, 'rev' => $this->_getLastMediaRevisionAt($src))) . '"'; } else { $ret .= '<img src="' . ml($src, array('w' => $width, 'h' => $height, 'cache' => $cache, 'rev' => $this->_getLastMediaRevisionAt($src))) . '"'; } $ret .= ' class="media' . $align . '"'; if ($title) { $ret .= ' title="' . $title . '"'; $ret .= ' alt="' . $title . '"'; } else { $ret .= ' alt=""'; } if (!is_null($width)) { $ret .= ' width="' . $this->_xmlEntities($width) . '"'; } if (!is_null($height)) { $ret .= ' height="' . $this->_xmlEntities($height) . '"'; } // add exif and gps info at the bottom of each image if ($ext == 'jpg' || $ext == 'jpeg') { //try to use the caption from IPTC/EXIF if (!$jepg) { require_once DOKU_INC . 'lib/plugins/colorbox/JpegMetaGPS.php'; $jpeg = new JpegMetaGPS(mediaFN($src)); } if ($jpeg !== false) { $infoshort = $jpeg->getShortExifInfo(); $info = $jpeg->getExifInfo(); $gpslink = $jpeg->getGPSInfo(); $ret .= ' exif="' . implode(';', array_map(function ($v, $k) { if ($v) { return strtolower($k) . ':' . $v . ''; } }, $infoshort, array_keys($infoshort))) . '"'; if ($gpslink) { $ret .= ' map="' . $gpslink . '"'; } $ret .= ' token="' . media_get_token($src, "1360", $height) . '"'; $ret .= '/></a>'; $ret .= '<div class="exiftitle">' . $title . '</div>'; $ret .= '<div class="exif">'; $ret .= implode(', ', array_map(function ($v, $k) { return $k . '=' . $v; }, $info, array_keys($info))); if ($gpslink) { $ret .= ' <a href=' . $gpslink . '>Google GPS Location'; } $ret .= ' </a></div>'; $ret .= '<a>'; } } // } elseif (media_supportedav($mime, 'video') || media_supportedav($mime, 'audio')) { // first get the $title $title = !is_null($title) ? $this->_xmlEntities($title) : false; if (!$render) { // if the file is not supposed to be rendered // return the title of the file (just the sourcename if there is no title) return $title ? $title : $this->_xmlEntities(utf8_basename(noNS($src))); } $att = array(); $att['class'] = "media{$align}"; if ($title) { $att['title'] = $title; } if (media_supportedav($mime, 'video')) { //add video $ret .= $this->_video($src, $width, $height, $att); } if (media_supportedav($mime, 'audio')) { //add audio $ret .= $this->_audio($src, $att); } } elseif ($mime == 'application/x-shockwave-flash') { if (!$render) { // if the flash is not supposed to be rendered // return the title of the flash if (!$title) { // just show the sourcename $title = utf8_basename(noNS($src)); } return $this->_xmlEntities($title); } $att = array(); $att['class'] = "media{$align}"; if ($align == 'right') { $att['align'] = 'right'; } if ($align == 'left') { $att['align'] = 'left'; } $ret .= html_flashobject(ml($src, array('cache' => $cache), true, '&'), $width, $height, array('quality' => 'high'), null, $att, $this->_xmlEntities($title)); } elseif ($title) { // well at least we have a title to display $ret .= $this->_xmlEntities($title); } else { // just show the sourcename $ret .= $this->_xmlEntities(utf8_basename(noNS($src))); } return $ret; }
/** * Defines how a thumbnail should look like */ function _image(&$img, $data) { global $ID; global $conf; // calculate thumbnail size if (!$data['crop']) { $w = (int) $this->_meta($img, 'width'); $h = (int) $this->_meta($img, 'height'); if ($conf['syslog']) { syslog(LOG_WARNING, '[gallery:syntax.php] image file: ' . $conf['mediadir'] . utf8_encodeFN(str_replace(':', '/', $img['id'])) . $img['file'] . '. size: ' . $w . 'x' . $h); } if ($w && $h) { $dim = array(); if ($w > $data['tw'] || $h > $data['th']) { $fr = $w / $h; if ($fr >= $data['tw'] / $data['th']) { $w = $data['tw']; $h = round($w / $fr); } else { $h = $data['th']; $w = round($h * $fr); } $dim = array('w' => $w, 'h' => $h); if ($conf['syslog']) { syslog(LOG_WARNING, '[gallery:syntax.php] image file: ' . $conf['mediadir'] . utf8_encodeFN(str_replace(':', '/', $img['id'])) . $img['file'] . '. reize to: ' . $w . 'x' . $h); } } } else { // this should not happen but if it does this usually means a corrupted image file therefore we want to log it syslog(LOG_WARNING, 'no size info found which is likely due to corrupted image file. force crop to ' . $data['tw'] . 'x' . $data['th'] . '. file: ' . $conf['mediadir'] . utf8_encodeFN(str_replace(':', '/', $img['id'])) . $img['file']); $data['crop'] = true; // no size info -> always crop } } if ($data['crop']) { $w = $data['tw']; $h = $data['th']; $dim = array('w' => $w, 'h' => $h); } //prepare img attributes $i = array(); $i['width'] = $w; $i['height'] = $h; $i['border'] = 0; if ($this->_meta($img, 'title')) { $i['alt'] = $this->_meta($img, 'title'); } else { $i['alt'] = end(explode(":", $img['id'])); } $i['longdesc'] = str_replace("\n", ' ', $this->_meta($img, 'desc')); if (!$i['longdesc']) { unset($i['longdesc']); } $i['class'] = 'tn'; // get exif and gps info $orientation = $img['meta']->getField("Orientation"); if ($conf['syslog']) { syslog(LOG_WARNING, '[gallery:syntax.php] orientation: ' . $orientation); } switch ($orientation) { case 6: if ($i['width'] > $i['height']) { // swap width and height if the image is going to be rotated vertically if ($conf['syslog']) { syslog(LOG_WARNING, 'swap width and height as the image is going to be rotated vertically'); } $old_width = $i['width']; $i['width'] = $i['height']; $i['height'] = $old_width; } break; case 8: if ($i['width'] > $i['height']) { // swap width and height if the image is going to be rotated vertically if ($conf['syslog']) { syslog(LOG_WARNING, 'swap width and height as the image is going to be rotated vertically'); } $old_width = $i['width']; $i['width'] = $i['height']; $i['height'] = $old_width; } break; } require_once DOKU_INC . 'lib/plugins/colorbox/JpegMetaGPS.php'; $jpeg = new JpegMetaGPS(mediaFN($img['id'])); if ($jpeg !== false) { $info = $jpeg->getShortExifInfo(); $gpslink = $jpeg->getGPSInfo(); if ($info) { $i['exif'] = implode(';', array_map(function ($v, $k) { if ($v) { return strtolower($k) . ':' . $v . ''; } }, $info, array_keys($info))); } if ($gpslink) { $i['map'] = $gpslink; } $i['token'] = media_get_token($img['id'], "1360", "0"); } $iatt = buildAttributes($i); $src = ml($img['id'], $dim); // prepare lightbox dimensions $w_lightbox = (int) $this->_meta($img, 'width'); $h_lightbox = (int) $this->_meta($img, 'height'); $dim_lightbox = array(); if ($w_lightbox > $data['iw'] || $h_lightbox > $data['ih']) { $ratio = $this->_ratio($img, $data['iw'], $data['ih']); $w_lightbox = floor($w_lightbox * $ratio); $h_lightbox = floor($h_lightbox * $ratio); $dim_lightbox = array('w' => $w_lightbox, 'h' => $h_lightbox); } //prepare link attributes $a = array(); $a['title'] = $this->_meta($img, 'title'); if ($data['lightbox']) { $href = ml($img['id'], $dim_lightbox); $a['class'] = "lightbox JSnocheck"; $a['rel'] = 'lightbox[gal-' . substr(md5($ID), 4) . ']'; //unique ID for the gallery } elseif ($img['detail'] && !$data['direct']) { $href = $img['detail']; } else { $href = ml($img['id'], array('id' => $ID), $data['direct']); } $aatt = buildAttributes($a); // prepare output $ret = ''; $ret .= '<a href="' . $href . '" ' . $aatt . '>'; $ret .= '<img src="' . $src . '" ' . $iatt . ' />'; $ret .= '</a>'; return $ret; }
/** * Defines how a thumbnail should look like */ function _image($data, &$renderer = null, $mode = 'xhtml') { global $ID; if (is_null($renderer) || empty($data['src'])) { return false; } if (!is_array($data['params'])) { $data['params'] = array(); } //prepare link attributes // can use reflected images $reflect = array(); if ($reflection = plugin_load('syntax', 'reflect')) { $reflect = array('reflect' => $this->getConf('reflect') ? 1 : 0, 'bgc' => $this->getConf('reflectBackground')); } // Start Section if ($mode != 'metadata') { $renderer->doc .= '<div class="imageflow_image">' . NL; } // Display $data['params']['tok'] = media_get_token($data['src'], $data['params']['w'], $data['params']['h']); $href = ml($data['src'], array_merge($data['params'], $reflect), true, '&'); if ($mode != 'metadata' && empty($data['alternate_desc'])) { $renderer->doc .= '<img src="' . $href . '" alt="" class="imageflow__noscript__image media"/>'; } // Set Data $fn = mediaFN($data['src']); $data['src'] = ml($data['src']); $data['params'] = array_merge($data['params'], $reflect); // Remove everything except the params. $data['desc'] = trim($data['desc']); $data['title'] = trim($data['title']); if (empty($data['desc']) && ($meta = new JpegMeta($fn))) { $data['title'] = $meta->getField('Iptc.Headline'); $data['desc'] = $meta->getField('Iptc.Caption'); } if ($mode != 'metadata') { if (!empty($data['alternate_desc'])) { $renderer->doc .= $data['alternate_desc']; } else { $renderer->doc .= '<div class="imageflow_caption">' . NL; if (!empty($data['title'])) { $renderer->doc .= "<h3 class=\"imageflow__title\">{$data['title']}</h3>" . NL; } if (!empty($data['desc'])) { $renderer->doc .= "<p class=\"imageflow__text\">{$data['desc']}</p>" . NL; } // End Caption $renderer->doc .= '</div>' . NL; } // End Section $renderer->doc .= '<div class="clearer"></div>' . NL . '</div>' . NL; } else { // Add Metadata unset($data['alternate_desc']); if (!$data['isImage'] && !empty($data['linkto'])) { $data['id'] = $data['linkto']; unset($data['linkto']); } $renderer->meta['relation']['imageflow'][$this->sectionID[sizeof($this->sectionID) - 1]][] = $data; } return $data; }