diff --git a/lib/file_api.php b/lib/file_api.php index 70f0dd9..b6d99f2 100644 --- a/lib/file_api.php +++ b/lib/file_api.php @@ -1,468 +1,497 @@ | +--------------------------------------------------------------------------+ | Author: Aleksander Machniak | +--------------------------------------------------------------------------+ */ class file_api extends file_api_core { public $session; public $config; public $browser; public $output_type = file_api_core::OUTPUT_JSON; public function __construct() { $rcube = rcube::get_instance(); $rcube->add_shutdown_function(array($this, 'shutdown')); $this->config = $rcube->config; $this->session_init(); } /** * Process the request and dispatch it to the requested service */ public function run() { $this->request = strtolower($_GET['method']); // Check the session, authenticate the user if (!$this->session_validate($this->request == 'authenticate')) { $this->session->destroy(session_id()); $this->session->regenerate_id(false); if ($username = $this->authenticate()) { // Init locale after the session started $this->locale_init(); $this->env['language'] = $this->language; $_SESSION['user'] = $username; $_SESSION['env'] = $this->env; // remember client API version if (is_numeric($_GET['version'])) { $_SESSION['version'] = $_GET['version']; } if ($this->request == 'authenticate') { $this->output_success(array( 'token' => session_id(), 'capabilities' => $this->capabilities(), )); } } else { throw new Exception("Invalid session", 403); } } else { // Init locale after the session started $this->locale_init(); } // Call service method $result = $this->request_handler($this->request); // Send success response, errors should be handled by driver class // by throwing exceptions or sending output by itself $this->output_success($result); } /** * Session validation check and session start */ private function session_validate($new_session = false) { if (!$new_session) { $sess_id = rcube_utils::request_header('X-Session-Token') ?: $_REQUEST['token']; } if (empty($sess_id)) { $this->session->start(); return false; } session_id($sess_id); $this->session->start(); if (empty($_SESSION['user'])) { return false; } // Document-only session if (($doc_id = $_SESSION['document_session']) && (strpos($this->request, 'document') !== 0 || $doc_id != $_GET['id']) ) { throw new Exception("Access denied", 403); } if ($_SESSION['env']) { $this->env = $_SESSION['env']; } return true; } /** * Initializes session */ private function session_init() { $rcube = rcube::get_instance(); $sess_name = $this->config->get('session_name'); $lifetime = $this->config->get('session_lifetime', 0) * 60; if ($lifetime) { ini_set('session.gc_maxlifetime', $lifetime * 2); } ini_set('session.name', $sess_name ? $sess_name : 'file_api_sessid'); ini_set('session.use_cookies', 0); ini_set('session.serialize_handler', 'php'); // Roundcube Framework >= 1.2 if (in_array('factory', get_class_methods('rcube_session'))) { $this->session = rcube_session::factory($this->config); } // Rouncube Framework < 1.2 else { $this->session = new rcube_session($rcube->get_dbh(), $this->config); $this->session->set_secret($this->config->get('des_key') . dirname($_SERVER['SCRIPT_NAME'])); $this->session->set_ip_check($this->config->get('ip_check')); } $this->session->register_gc_handler(array($rcube, 'gc')); // this is needed to correctly close session in shutdown function $rcube->session = $this->session; } /** * Script shutdown handler */ public function shutdown() { // write performance stats to logs/console if ($this->config->get('devel_mode')) { if (function_exists('memory_get_peak_usage')) $mem = memory_get_peak_usage(); else if (function_exists('memory_get_usage')) $mem = memory_get_usage(); $log = trim($this->request . ($mem ? sprintf(' [%.1f MB]', $mem/1024/1024) : '')); if (defined('FILE_API_START')) { rcube::print_timer(FILE_API_START, $log); } else { rcube::console($log); } } } /** * Authentication request handler (HTTP Auth) */ private function authenticate() { if (isset($_POST['username'])) { $username = $_POST['username']; $password = $_POST['password']; } else if (!empty($_SERVER['PHP_AUTH_USER'])) { $username = $_SERVER['PHP_AUTH_USER']; $password = $_SERVER['PHP_AUTH_PW']; } // when used with (f)cgi no PHP_AUTH* variables are available without defining a special rewrite rule else if (!isset($_SERVER['PHP_AUTH_USER'])) { // "Basic didhfiefdhfu4fjfjdsa34drsdfterrde..." if (isset($_SERVER["REMOTE_USER"])) { $basicAuthData = base64_decode(substr($_SERVER["REMOTE_USER"], 6)); } else if (isset($_SERVER["REDIRECT_REMOTE_USER"])) { $basicAuthData = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6)); } else if (isset($_SERVER["Authorization"])) { $basicAuthData = base64_decode(substr($_SERVER["Authorization"], 6)); } else if (isset($_SERVER["HTTP_AUTHORIZATION"])) { $basicAuthData = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)); } if (isset($basicAuthData) && !empty($basicAuthData)) { list($username, $password) = explode(":", $basicAuthData); } } if (!empty($username)) { $backend = $this->get_backend(); $result = $backend->authenticate($username, $password); if (empty($result)) { /* header('WWW-Authenticate: Basic realm="' . $this->app_name .'"'); header('HTTP/1.1 401 Unauthorized'); exit; */ throw new Exception("Invalid password or username", file_api_core::ERROR_CODE); } } return $username; } /** * Storage/System method handler */ private function request_handler($request) { // handle "global" requests that don't require api driver switch ($request) { case 'ping': return array(); case 'quit': $this->session->destroy(session_id()); return array(); case 'configure': foreach (array_keys($this->env) as $name) { if (isset($_GET[$name])) { $this->env[$name] = $_GET[$name]; } } $_SESSION['env'] = $this->env; return $this->env; case 'upload_progress': return $this->upload_progress(); case 'mimetypes': return $this->supported_mimetypes(); case 'capabilities': return $this->capabilities(); } // handle request if ($request && preg_match('/^[a-z0-9_-]+$/', $request)) { $aliases = array( // request name aliases for backward compatibility 'lock' => 'lock_create', 'unlock' => 'lock_delete', 'folder_rename' => 'folder_move', ); // Redirect all document_* actions into 'document' action if (preg_match('/^(sessions|invitations|document_[a-z]+)$/', $request)) { $request = 'document'; } $request = $aliases[$request] ?: $request; require_once __DIR__ . "/api/common.php"; include_once __DIR__ . "/api/$request.php"; $class_name = "file_api_$request"; if (class_exists($class_name, false)) { $handler = new $class_name($this); return $handler->handle(); } } throw new Exception("Unknown method", file_api_core::ERROR_INVALID); } /** * File upload progress handler */ protected function upload_progress() { if (function_exists('apc_fetch')) { $prefix = ini_get('apc.rfc1867_prefix'); $uploadid = rcube_utils::get_input_value('id', rcube_utils::INPUT_GET); $status = apc_fetch($prefix . $uploadid); if (!empty($status)) { $status['percent'] = round($status['current']/$status['total']*100); if ($status['percent'] < 100) { $diff = max(1, time() - intval($status['start_time'])); // calculate time to end of uploading (in seconds) $status['eta'] = intval($diff * (100 - $status['percent']) / $status['percent']); // average speed (bytes per second) $status['rate'] = intval($status['current'] / $diff); } } $status['id'] = $uploadid; return $status; // id, done, total, current, percent, start_time, eta, rate } throw new Exception("Not supported", file_api_core::ERROR_CODE); } /** * Returns complete File URL * * @param string $file File name (with path) * * @return string File URL */ public function file_url($file) { - return file_utils::script_uri(). '?method=file_get' + return $this->api_url() . '?method=file_get' . '&file=' . urlencode($file) . '&token=' . urlencode(session_id()); } + /** + * Returns API URL + * + * @return string API URL + */ + public function api_url() + { + $api_url = $this->config->get('file_api_url', ''); + + if (!preg_match('|^https?://|', $url)) { + $schema = rcube_utils::https_check() ? 'https' : 'http'; + $port = $schema == 'http' ? 80 : 443; + $url = $schema . '://' . $_SERVER['SERVER_NAME']; + $url .= $_SERVER['SERVER_PORT'] != $port ? ':' . $_SERVER['SERVER_PORT'] : ''; + + if ($api_url) { + $api_url = $url . '/' . trim($api_url, '/ '); + } + else { + $url .= preg_replace('/\/?\?.*$/', '', $_SERVER['REQUEST_URI']); + $url = preg_replace('/\/api$/', '', $url); + + $api_url = $url . '/api'; + } + } + + return rtrim($api_url, '/ '); + } + /** * Returns web browser object * * @return rcube_browser Web browser object */ public function get_browser() { if ($this->browser === null) { $this->browser = new rcube_browser; } return $this->browser; } /** * Send success response * * @param mixed $data Data */ public function output_success($data) { if (!is_array($data)) { $data = array(); } $response = array('status' => 'OK', 'result' => $data); if (!empty($_REQUEST['req_id'])) { $response['req_id'] = $_REQUEST['req_id']; } $this->output_send($response); } /** * Send error response * * @param mixed $response Response data * @param int $code Error code */ public function output_error($response, $code = null) { if (is_string($response)) { $response = array('reason' => $response); } $response['status'] = 'ERROR'; if ($code) { $response['code'] = $code; } if (!empty($_REQUEST['req_id'])) { $response['req_id'] = $_REQUEST['req_id']; header("X-Chwala-Request-ID: " . $_REQUEST['req_id']); } if (empty($response['code'])) { $response['code'] = file_api_core::ERROR_CODE; } header("X-Chwala-Error: " . $response['code']); // When binary response is expected return real // HTTP error instaead of JSON response with code 200 if ($this->is_binary_request()) { header(sprintf("HTTP/1.0 %d %s", $response['code'], $response ?: "Server error")); exit; } $this->output_send($response); } /** * Send response * * @param mixed $data Data */ protected function output_send($data) { // Send response header("Content-Type: {$this->output_type}; charset=utf-8"); echo json_encode($data); exit; } /** * Find out if current request expects binary output */ protected function is_binary_request() { return preg_match('/^(file_get|document)$/', $this->request) && $_SERVER['REQUEST_METHOD'] == 'GET'; } /** * Returns API version supported by the client */ public function client_version() { return $_SESSION['version']; } /** * Create a human readable string for a number of bytes * * @param int Number of bytes * * @return string Byte string */ public function show_bytes($bytes) { if ($bytes >= 1073741824) { $gb = $bytes/1073741824; $str = sprintf($gb >= 10 ? "%d " : "%.1f ", $gb) . 'GB'; } else if ($bytes >= 1048576) { $mb = $bytes/1048576; $str = sprintf($mb >= 10 ? "%d " : "%.1f ", $mb) . 'MB'; } else if ($bytes >= 1024) { $str = sprintf("%d ", round($bytes/1024)) . 'KB'; } else { $str = sprintf('%d ', $bytes) . 'B'; } return $str; } } diff --git a/lib/file_utils.php b/lib/file_utils.php index 52ed686..c718f11 100644 --- a/lib/file_utils.php +++ b/lib/file_utils.php @@ -1,266 +1,248 @@ | +--------------------------------------------------------------------------+ | Author: Aleksander Machniak | +--------------------------------------------------------------------------+ */ class file_utils { static $class_map = array( 'document' => array( // text 'text/', 'application/rtf', 'application/x-rtf', 'application/xml', // office 'application/wordperfect', 'application/excel', 'application/msword', 'application/msexcel', 'application/mspowerpoint', 'application/vnd.ms-word', 'application/vnd.ms-excel', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument', 'application/vnd.oasis.opendocument', 'application/vnd.sun.xml.calc', 'application/vnd.sun.xml.writer', 'application/vnd.stardivision.calc', 'application/vnd.stardivision.writer', // pdf 'application/pdf', 'application/x-pdf', 'application/acrobat', 'application/vnd.pdf', ), 'audio' => array( 'audio/', ), 'video' => array( 'video/', ), 'image' => array( 'image/', 'application/dxf', 'application/acad', ), 'empty' => array( 'application/x-empty', ), ); // list of known file extensions, more in Roundcube config static $ext_map = array( 'doc' => 'application/msword', 'eml' => 'message/rfc822', 'gz' => 'application/gzip', 'htm' => 'text/html', 'html' => 'text/html', 'mp3' => 'audio/mpeg', 'odp' => 'application/vnd.oasis.opendocument.presentation', 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', 'odt' => 'application/vnd.oasis.opendocument.text', 'ogg' => 'application/ogg', 'pdf' => 'application/pdf', 'ppt' => 'application/vnd.ms-powerpoint', 'rar' => 'application/x-rar-compressed', 'tgz' => 'application/gzip', 'txt' => 'text/plain', 'zip' => 'application/zip', ); /** * Return list of mimetype prefixes for specified file class * * @param string $class Class name * * @return array List of mimetype prefixes */ static function class2mimetypes($class) { return isset(self::$class_map[$class]) ? self::$class_map[$class] : self::$class_map['empty']; } /** * Finds class of specified mimetype * * @param string $mimetype File mimetype * * @return string Class name */ static function mimetype2class($mimetype) { $mimetype = strtolower($mimetype); foreach (self::$class_map as $class => $prefixes) { foreach ($prefixes as $prefix) { if (strpos($mimetype, $prefix) === 0) { return $class; } } } } /** * Apply some fixes on file mimetype string * * @param string $mimetype File type * * @return string File type */ static function real_mimetype($mimetype) { if (preg_match('/^text\/(.+)/i', $mimetype, $m)) { // fix pdf mimetype if (preg_match('/^(pdf|x-pdf)$/i', $m[1])) { $mimetype = 'application/pdf'; } } return $mimetype; } /** * Find mimetype from file name (extension) * * @param string $filename File name * @param string $fallback Follback mimetype * * @return string File mimetype */ static function ext_to_type($filename, $fallback = 'application/octet-stream') { static $mime_ext = array(); $config = rcube::get_instance()->config; $ext = substr($filename, strrpos($filename, '.') + 1); if (empty($mime_ext)) { $mime_ext = self::$ext_map; foreach ($config->resolve_paths('mimetypes.php') as $fpath) { $mime_ext = array_merge($mime_ext, (array) @include($fpath)); } } if (is_array($mime_ext) && $ext) { $mimetype = $mime_ext[strtolower($ext)]; } return $mimetype ?: $fallback; } - /** - * Returns script URI - * - * @return string Script URI - */ - static function script_uri() - { - if (!empty($_SERVER['SCRIPT_URI'])) { - return $_SERVER['SCRIPT_URI']; - } - - $uri = $_SERVER['SERVER_PORT'] == 443 ? 'https://' : 'http://'; - $uri .= $_SERVER['HTTP_HOST']; - $uri .= preg_replace('/\?.*$/', '', $_SERVER['REQUEST_URI']); - - return $uri; - } - /** * Callback for uasort() that implements correct * locale-aware case-sensitive sorting */ public static function sort_folder_comparator($p1, $p2) { $ext = is_array($p1); // folder can be a string or an array with 'folder' key $path1 = explode(file_storage::SEPARATOR, $ext ? $p1['folder'] : $p1); $path2 = explode(file_storage::SEPARATOR, $ext ? $p2['folder'] : $p2); foreach ($path1 as $idx => $folder1) { $folder2 = $path2[$idx]; if ($folder1 === $folder2) { continue; } return strcoll($folder1, $folder2); } return 0; } /** * Encode folder path for use in an URI * * @param string $path Folder path * * @return string Encoded path */ public static function encode_path($path) { $items = explode(file_storage::SEPARATOR, $path); $items = array_map('rawurlencode', $items); return implode(file_storage::SEPARATOR, $items); } /** * Decode an URI into folder path * * @param string $path Encoded folder path * * @return string Decoded path */ public static function decode_path($path) { $items = explode(file_storage::SEPARATOR, $path); $items = array_map('rawurldecode', $items); return implode(file_storage::SEPARATOR, $items); } /** * * @return string Date time string in specified format and timezone */ public static function date_format($datetime, $format = 'Y-m-d H:i', $timezone = null) { if (!$datetime instanceof DateTime) { return ''; } if ($timezone && $timezone != $datetime->getTimezone()) { try { $dt = clone $datetime; $dt->setTimezone(new DateTimeZone($timezone)); $datetime = $dt; } catch (Exception $e) { // ignore, return original timezone } } return $datetime->format($format); } } diff --git a/lib/viewers/doc.php b/lib/viewers/doc.php index 0a80e7c..c749f81 100644 --- a/lib/viewers/doc.php +++ b/lib/viewers/doc.php @@ -1,133 +1,130 @@ | +--------------------------------------------------------------------------+ | Author: Aleksander Machniak | +--------------------------------------------------------------------------+ */ /** * Class integrating Collabora Online documents viewer */ class file_viewer_doc extends file_viewer { /** * Class constructor * * @param file_api File API object */ public function __construct($api) { $this->api = $api; } /** * Returns list of supported mimetype * * @return array List of mimetypes */ public function supported_mimetypes() { $rcube = rcube::get_instance(); // Get list of supported types from Collabora if ($rcube->config->get('fileapi_wopi_office')) { $wopi = new file_wopi($this->api); if ($types = $wopi->supported_filetypes()) { return $types; } } return array(); } /** * Check if mimetype is supported by the viewer * * @param string $mimetype File type * * @return bool True if mimetype is supported, False otherwise */ public function supports($mimetype) { return in_array($mimetype, $this->supported_mimetypes()); } /** * Return file viewer URL * * @param string $file File name * @param string $mimetype File type */ public function href($file, $mimetype = null) { - return file_utils::script_uri() . '?method=file_get' - . '&viewer=doc' - . '&file=' . urlencode($file) - . '&token=' . urlencode(session_id()); + return $this->api->file_url($file) . '&viewer=doc'; } /** * Print output and exit * * @param string $file File name * @param array $file_info File metadata (e.g. type) */ public function output($file, $file_info = array()) { // Create readonly session and get WOPI request parameters $wopi = new file_wopi($this->api); $url = $wopi->session_start($file, $file_info, $session, true); if (!$url) { $this->api->output_error("Failed to open file", 404); } $info = array('readonly' => true); $post = $wopi->editor_post_params($info); $url = htmlentities($url); $form = ''; foreach ($post as $name => $value) { $form .= ''; } echo <<
$form
EOT; } } diff --git a/lib/viewers/image.php b/lib/viewers/image.php index 96ced54..409c456 100644 --- a/lib/viewers/image.php +++ b/lib/viewers/image.php @@ -1,111 +1,109 @@ | +--------------------------------------------------------------------------+ | Author: Aleksander Machniak | +--------------------------------------------------------------------------+ */ /** * Class implementing image viewer (with format converter) * * NOTE: some formats are supported by browser, don't use viewer when not needed. */ class file_viewer_image extends file_viewer { protected $mimetypes = array( 'image/bmp', 'image/png', 'image/jpeg', 'image/jpg', 'image/pjpeg', 'image/gif', 'image/tiff', 'image/x-tiff', ); /** * Class constructor * * @param file_api File API object */ public function __construct($api) { // @TODO: disable types not supported by some browsers $this->api = $api; } /** * Return file viewer URL * * @param string $file File name * @param string $mimetype File type */ public function href($file, $mimetype = null) { - $href = file_utils::script_uri() . '?method=file_get' - . '&file=' . urlencode($file) - . '&token=' . urlencode(session_id()); + $href = $this->api->file_url($file); // we redirect to self only images with types unsupported // by browser if (in_array($mimetype, $this->mimetypes)) { $href .= '&viewer=image'; } return $href; } /** * Print output and exit * * @param string $file File name * @param array $file_info File metadata (e.g. type) */ public function output($file, $file_info = array()) { /* // conversion not needed if (preg_match('/^image/p?jpe?g$/i', $file_info['type'])) { $this->api->api->file_get($file); return; } */ $rcube = rcube::get_instance(); $temp_dir = unslashify($rcube->config->get('temp_dir')); $file_path = tempnam($temp_dir, 'rcmImage'); list($driver, $file) = $this->api->get_driver($file); // write content to temp file $fd = fopen($file_path, 'w'); $driver->file_get($file, array(), $fd); fclose($fd); // convert image to jpeg and send it to the browser $image = new rcube_image($file_path); if ($image->convert(rcube_image::TYPE_JPG, $file_path)) { header("Content-Type: image/jpeg"); header("Content-Length: " . filesize($file_path)); readfile($file_path); } unlink($file_path); } } diff --git a/lib/viewers/media.php b/lib/viewers/media.php index dfe5d7b..f240d0e 100644 --- a/lib/viewers/media.php +++ b/lib/viewers/media.php @@ -1,106 +1,106 @@ | +--------------------------------------------------------------------------+ | Author: Aleksander Machniak | +--------------------------------------------------------------------------+ */ /** * Class integrating HTML5 audio/video player from http://mediaelementjs.com */ class file_viewer_media extends file_viewer { protected $mimetypes = array( 'video/mp4', 'video/m4v', 'video/ogg', 'video/webm', // 'video/3gpp', // 'video/flv', // 'video/x-flv', 'application/ogg', 'audio/mp3', 'audio/mpeg', 'audio/ogg', 'audio/wav', 'audio/flv', 'audio/x-mpeg', 'audio/x-ogg', 'audio/x-wav', 'audio/x-flv', ); /** * Class constructor * * @param file_api File API object */ public function __construct($api) { // @TODO: disable types not supported by some browsers $this->api = $api; } /** * Return output of file content area * * @param string $file File name * @param string $mimetype File type */ public function frame($file, $mimetype = null) { - $path = file_utils::script_uri(); + $path = $this->api->api_url(); $file_uri = htmlentities($this->api->file_url($file)); $mimetype = htmlentities($mimetype); $source = ""; if (preg_match('/^audio/', $mimetype)) { $tag = 'audio'; } else { $tag = 'video'; } return << - + + <$tag id="media-player" controls preload="auto">$source EOT; } } diff --git a/lib/viewers/odf.php b/lib/viewers/odf.php index c285908..45b210d 100644 --- a/lib/viewers/odf.php +++ b/lib/viewers/odf.php @@ -1,136 +1,133 @@ | +--------------------------------------------------------------------------+ | Author: Aleksander Machniak | +--------------------------------------------------------------------------+ */ /** * Class integrating ODF documents viewer from http://webodf.org */ class file_viewer_odf extends file_viewer { protected $mimetypes = array( 'application/vnd.oasis.opendocument.text', 'application/vnd.oasis.opendocument.spreadsheet', 'application/vnd.oasis.opendocument.presentation', 'application/vnd.oasis.opendocument.graphics', 'application/vnd.oasis.opendocument.chart', // 'application/vnd.oasis.opendocument.formula', 'application/vnd.oasis.opendocument.image', 'application/vnd.oasis.opendocument.text-master', // 'application/vnd.sun.xml.base', // 'application/vnd.oasis.opendocument.base', // 'application/vnd.oasis.opendocument.database', 'application/vnd.oasis.opendocument.text-template', 'application/vnd.oasis.opendocument.spreadsheet-template', 'application/vnd.oasis.opendocument.presentation-template', 'application/vnd.oasis.opendocument.graphics-template', 'application/vnd.oasis.opendocument.chart-template', // 'application/vnd.oasis.opendocument.formula-template', 'application/vnd.oasis.opendocument.image-template', ); /** * Class constructor * * @param file_api File API object */ public function __construct($api) { $this->api = $api; $browser = $api->get_browser(); // disable viewer in unsupported browsers if ($browser->ie && $browser->ver < 9) { $this->mimetypes = array(); } } /** * Returns list of supported mimetype * * @return array List of mimetypes */ public function supported_mimetypes() { // @TODO: check supported browsers return $this->mimetypes; } /** * Check if mimetype is supported by the viewer * * @param string $mimetype File type * * @return bool */ public function supports($mimetype) { return in_array($mimetype, $this->mimetypes); } /** * Return file viewer URL * * @param string $file File name * @param string $mimetype File type */ public function href($file, $mimetype = null) { - return file_utils::script_uri() . '?method=file_get' - . '&viewer=odf' - . '&file=' . urlencode($file) - . '&token=' . urlencode(session_id()); + return $this->api->file_url($file) . '&viewer=odf'; } /** * Print output and exit * * @param string $file File name * @param array $file_info File metadata (e.g. type) */ public function output($file, $file_info = array()) { $file_uri = $this->api->file_url($file); echo <<
EOT; } } diff --git a/lib/viewers/pdf.php b/lib/viewers/pdf.php index cd69619..affa048 100644 --- a/lib/viewers/pdf.php +++ b/lib/viewers/pdf.php @@ -1,73 +1,73 @@ | +--------------------------------------------------------------------------+ | Author: Aleksander Machniak | +--------------------------------------------------------------------------+ */ /** * Class integrating PDF viewer from https://github.com/mozilla/pdf.js */ class file_viewer_pdf extends file_viewer { protected $mimetypes = array( 'application/pdf', 'application/x-pdf', 'application/acrobat', 'applications/vnd.pdf', 'text/pdf', 'text/x-pdf', ); /** * Class constructor * * @param file_api File API object */ public function __construct($api) { $this->api = $api; $browser = $api->get_browser(); // disable viewer in unsupported browsers according to // https://github.com/mozilla/pdf.js/wiki/Required-Browser-Features if (($browser->ie && $browser->ver < 9) || ($browser->opera && $browser->ver < 9.5) || ($browser->chrome && $browser->ver < 24) || ($browser->safari && $browser->ver < 5) || ($browser->mz && $browser->ver < 6) ) { $this->mimetypes = array(); } } /** * Return file viewer URL * * @param string $file File name * @param string $mimetype File type */ public function href($file, $mimetype = null) { - return file_utils::script_uri() . 'viewers/pdf/viewer.html' + return $this->api->api_url() . '/viewers/pdf/viewer.html' . '?file=' . urlencode($this->api->file_url($file)); } }