1<?php 2/* Copyright (C) 2004-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org> 3 * Copyright (C) 2005-2016 Laurent Destailleur <eldy@users.sourceforge.net> 4 * Copyright (C) 2005-2016 Regis Houssin <regis.houssin@inodbox.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <https://www.gnu.org/licenses/>. 18 * or see https://www.gnu.org/ 19 */ 20 21/** 22 * \file htdocs/viewimage.php 23 * \brief Wrapper to show images into Dolibarr screens. 24 * \remarks Call to wrapper is : 25 * DOL_URL_ROOT.'/viewimage.php?modulepart=diroffile&file=relativepathofofile&cache=0 26 * DOL_URL_ROOT.'/viewimage.php?hashp=sharekey 27 */ 28 29//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER','1'); // Not disabled cause need to load personalized language 30//if (! defined('NOREQUIREDB')) define('NOREQUIREDB','1'); // Not disabled cause need to load personalized language 31if (!defined('NOREQUIRESOC')) { 32 define('NOREQUIRESOC', '1'); 33} 34if (!defined('NOREQUIRETRAN')) { 35 define('NOREQUIRETRAN', '1'); 36} 37if (!defined('NOCSRFCHECK')) { 38 define('NOCSRFCHECK', '1'); 39} 40if (!defined('NOTOKENRENEWAL')) { 41 define('NOTOKENRENEWAL', '1'); 42} 43if (!defined('NOREQUIREMENU')) { 44 define('NOREQUIREMENU', '1'); 45} 46if (!defined('NOREQUIREHTML')) { 47 define('NOREQUIREHTML', '1'); 48} 49if (!defined('NOREQUIREAJAX')) { 50 define('NOREQUIREAJAX', '1'); 51} 52 53// Some value of modulepart can be used to get resources that are public so no login are required. 54// Note that only directory logo is free to access without login. 55if (isset($_GET["modulepart"]) && $_GET["modulepart"] == 'mycompany' && preg_match('/^\/?logos\//', $_GET['file'])) { 56 if (!defined("NOLOGIN")) { 57 define("NOLOGIN", 1); 58 } 59 if (!defined("NOCSRFCHECK")) { 60 define("NOCSRFCHECK", 1); // We accept to go on this page from external web site. 61 } 62 if (!defined("NOIPCHECK")) { 63 define("NOIPCHECK", 1); // Do not check IP defined into conf $dolibarr_main_restrict_ip 64 } 65} 66// For direct external download link, we don't need to load/check we are into a login session 67if (isset($_GET["hashp"]) && !defined("NOLOGIN")) { 68 if (!defined("NOLOGIN")) { 69 define("NOLOGIN", 1); 70 } 71 if (!defined("NOCSRFCHECK")) { 72 define("NOCSRFCHECK", 1); // We accept to go on this page from external web site. 73 } 74 if (!defined("NOIPCHECK")) { 75 define("NOIPCHECK", 1); // Do not check IP defined into conf $dolibarr_main_restrict_ip 76 } 77} 78// Some value of modulepart can be used to get resources that are public so no login are required. 79if (isset($_GET["modulepart"]) && $_GET["modulepart"] == 'medias') { 80 if (!defined("NOLOGIN")) { 81 define("NOLOGIN", 1); 82 } 83 if (!defined("NOCSRFCHECK")) { 84 define("NOCSRFCHECK", 1); // We accept to go on this page from external web site. 85 } 86 if (!defined("NOIPCHECK")) { 87 define("NOIPCHECK", 1); // Do not check IP defined into conf $dolibarr_main_restrict_ip 88 } 89} 90 91// Used by TakePOS Auto Order 92if (isset($_GET["modulepart"]) && $_GET["modulepart"] == 'product' && isset($_GET["publictakepos"])) { 93 if (!defined("NOLOGIN")) { 94 define("NOLOGIN", 1); 95 } 96 if (!defined("NOCSRFCHECK")) { 97 define("NOCSRFCHECK", 1); // We accept to go on this page from external web site. 98 } 99 if (!defined("NOIPCHECK")) { 100 define("NOIPCHECK", 1); // Do not check IP defined into conf $dolibarr_main_restrict_ip 101 } 102} 103 104// For multicompany 105$entity = (!empty($_GET['entity']) ? (int) $_GET['entity'] : (!empty($_POST['entity']) ? (int) $_POST['entity'] : 1)); 106if (is_numeric($entity)) { 107 define("DOLENTITY", $entity); 108} 109 110/** 111 * Header empty 112 * 113 * @ignore 114 * @return void 115 */ 116function llxHeader() 117{ 118} 119/** 120 * Footer empty 121 * 122 * @ignore 123 * @return void 124 */ 125function llxFooter() 126{ 127} 128 129require 'main.inc.php'; // Load $user and permissions 130require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; 131 132$action = GETPOST('action', 'aZ09'); 133$original_file = GETPOST('file', 'alphanohtml'); // Do not use urldecode here ($_GET are already decoded by PHP). 134$hashp = GETPOST('hashp', 'aZ09'); 135$modulepart = GETPOST('modulepart', 'alpha'); 136$urlsource = GETPOST('urlsource', 'alpha'); 137$entity = GETPOST('entity', 'int') ?GETPOST('entity', 'int') : $conf->entity; 138 139// Security check 140if (empty($modulepart) && empty($hashp)) { 141 accessforbidden('Bad link. Bad value for parameter modulepart', 0, 0, 1); 142} 143if (empty($original_file) && empty($hashp) && $modulepart != 'barcode') { 144 accessforbidden('Bad link. Missing identification to find file (param file or hashp)', 0, 0, 1); 145} 146if ($modulepart == 'fckeditor') { 147 $modulepart = 'medias'; // For backward compatibility 148} 149 150 151 152/* 153 * Actions 154 */ 155 156// None 157 158 159 160/* 161 * View 162 */ 163 164if (GETPOST("cache", 'alpha')) { 165 // Important: Following code is to avoid page request by browser and PHP CPU at 166 // each Dolibarr page access. 167 if (empty($dolibarr_nocache)) { 168 header('Cache-Control: max-age=3600, public, must-revalidate'); 169 header('Pragma: cache'); // This is to avoid having Pragma: no-cache 170 } else { 171 header('Cache-Control: no-cache'); 172 } 173 //print $dolibarr_nocache; exit; 174} 175 176// If we have a hash public (hashp), we guess the original_file. 177if (!empty($hashp)) { 178 include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php'; 179 $ecmfile = new EcmFiles($db); 180 $result = $ecmfile->fetch(0, '', '', '', $hashp); 181 if ($result > 0) { 182 $tmp = explode('/', $ecmfile->filepath, 2); // $ecmfile->filepath is relative to document directory 183 // filepath can be 'users/X' or 'X/propale/PR11111' 184 if (is_numeric($tmp[0])) { // If first tmp is numeric, it is subdir of company for multicompany, we take next part. 185 $tmp = explode('/', $tmp[1], 2); 186 } 187 $moduleparttocheck = $tmp[0]; // moduleparttocheck is first part of path 188 189 if ($modulepart) { // Not required, so often not defined, for link using public hashp parameter. 190 if ($moduleparttocheck == $modulepart) { 191 // We remove first level of directory 192 $original_file = (($tmp[1] ? $tmp[1].'/' : '').$ecmfile->filename); // this is relative to module dir 193 //var_dump($original_file); exit; 194 } else { 195 accessforbidden('Bad link. File is from another module part.', 0, 0, 1); 196 } 197 } else { 198 $modulepart = $moduleparttocheck; 199 $original_file = (($tmp[1] ? $tmp[1].'/' : '').$ecmfile->filename); // this is relative to module dir 200 } 201 } else { 202 $langs->load("errors"); 203 accessforbidden($langs->trans("ErrorFileNotFoundWithSharedLink"), 0, 0, 1); 204 } 205} 206 207// Define mime type 208$type = 'application/octet-stream'; 209if (GETPOST('type', 'alpha')) { 210 $type = GETPOST('type', 'alpha'); 211} else { 212 $type = dol_mimetype($original_file); 213} 214 215// Security: This wrapper is for images. We do not allow type/html 216if (preg_match('/html/i', $type)) { 217 accessforbidden('Error: Using the image wrapper to output a file with a mime type HTML is not possible.', 0, 0, 1); 218} 219// Security: This wrapper is for images. We do not allow files ending with .noexe 220if (preg_match('/\.noexe$/i', $original_file)) { 221 accessforbidden('Error: Using the image wrapper to output a file ending with .noexe is not allowed.', 0, 0, 1); 222} 223 224// Security: Delete string ../ or ..\ into $original_file 225$original_file = str_replace('../', '/', $original_file); 226$original_file = str_replace('..\\', '/', $original_file); 227 228// Find the subdirectory name as the reference 229$refname = basename(dirname($original_file)."/"); 230 231// Security check 232if (empty($modulepart)) { 233 accessforbidden('Bad value for parameter modulepart', 0, 0, 1); 234} 235 236$check_access = dol_check_secure_access_document($modulepart, $original_file, $entity, $refname); 237$accessallowed = $check_access['accessallowed']; 238$sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals']; 239$fullpath_original_file = $check_access['original_file']; // $fullpath_original_file is now a full path name 240 241if (!empty($hashp)) { 242 $accessallowed = 1; // When using hashp, link is public so we force $accessallowed 243 $sqlprotectagainstexternals = ''; 244} elseif (isset($_GET["publictakepos"])) { 245 if (!empty($conf->global->TAKEPOS_AUTO_ORDER)) { 246 $accessallowed = 1; // Only if TakePOS Public Auto Order is enabled and received publictakepos variable 247 } 248} else { 249 // Basic protection (against external users only) 250 if ($user->socid > 0) { 251 if ($sqlprotectagainstexternals) { 252 $resql = $db->query($sqlprotectagainstexternals); 253 if ($resql) { 254 $num = $db->num_rows($resql); 255 $i = 0; 256 while ($i < $num) { 257 $obj = $db->fetch_object($resql); 258 if ($user->socid != $obj->fk_soc) { 259 $accessallowed = 0; 260 break; 261 } 262 $i++; 263 } 264 } 265 } 266 } 267} 268 269// Security: 270// Limit access if permissions are wrong 271if (!$accessallowed) { 272 accessforbidden(); 273} 274 275// Security: 276// On interdit les remontees de repertoire ainsi que les pipe dans les noms de fichiers. 277if (preg_match('/\.\./', $fullpath_original_file) || preg_match('/[<>|]/', $fullpath_original_file)) { 278 dol_syslog("Refused to deliver file ".$fullpath_original_file); 279 print "ErrorFileNameInvalid: ".dol_escape_htmltag($original_file); 280 exit; 281} 282 283 284 285if ($modulepart == 'barcode') { 286 $generator = GETPOST("generator", "aZ09"); 287 $encoding = GETPOST("encoding", "aZ09"); 288 $readable = GETPOST("readable", 'aZ09') ? GETPOST("readable", "aZ09") : "Y"; 289 if (in_array($encoding, array('EAN8', 'EAN13'))) { 290 $code = GETPOST("code", 'alphanohtml'); 291 } else { 292 $code = GETPOST("code", 'none'); // This can be rich content (qrcode, datamatrix, ...) 293 } 294 295 if (empty($generator) || empty($encoding)) { 296 print 'Error: Parameter "generator" or "encoding" not defined'; 297 exit; 298 } 299 300 $dirbarcode = array_merge(array("/core/modules/barcode/doc/"), $conf->modules_parts['barcode']); 301 302 $result = 0; 303 304 foreach ($dirbarcode as $reldir) { 305 $dir = dol_buildpath($reldir, 0); 306 $newdir = dol_osencode($dir); 307 308 // Check if directory exists (we do not use dol_is_dir to avoid loading files.lib.php) 309 if (!is_dir($newdir)) { 310 continue; 311 } 312 313 $result = @include_once $newdir.$generator.'.modules.php'; 314 if ($result) { 315 break; 316 } 317 } 318 319 // Load barcode class 320 $classname = "mod".ucfirst($generator); 321 $module = new $classname($db); 322 if ($module->encodingIsSupported($encoding)) { 323 $result = $module->buildBarCode($code, $encoding, $readable); 324 } 325} else { 326 // Open and return file 327 clearstatcache(); 328 329 $filename = basename($fullpath_original_file); 330 331 // Output files on browser 332 dol_syslog("viewimage.php return file $fullpath_original_file filename=$filename content-type=$type"); 333 334 // This test is to avoid error images when image is not available (for example thumbs). 335 if (!dol_is_file($fullpath_original_file) && empty($_GET["noalt"])) { 336 $fullpath_original_file = DOL_DOCUMENT_ROOT.'/public/theme/common/nophoto.png'; 337 /*$error='Error: File '.$_GET["file"].' does not exists or filesystems permissions are not allowed'; 338 print $error; 339 exit;*/ 340 } 341 342 // Permissions are ok and file found, so we return it 343 if ($type) { 344 top_httphead($type); 345 header('Content-Disposition: inline; filename="'.basename($fullpath_original_file).'"'); 346 } else { 347 top_httphead('image/png'); 348 header('Content-Disposition: inline; filename="'.basename($fullpath_original_file).'"'); 349 } 350 351 $fullpath_original_file_osencoded = dol_osencode($fullpath_original_file); 352 353 readfile($fullpath_original_file_osencoded); 354} 355 356 357if (is_object($db)) { 358 $db->close(); 359} 360