forked from Wavyzz/dolibarr
* Qual: Spelling fixes that newly appeared. # Qual: Fix spelling erros that appeared since the bulk updates. These issues mostly appeared since the bulk updates (a few ones were postponed to make sure no real spelling errors were missed.) * Update modulebuilder.lib.php * Update pdf_standard.modules.php --------- Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
378 lines
12 KiB
PHP
378 lines
12 KiB
PHP
<?php
|
|
/* Copyright (C) 2004-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
|
|
* Copyright (C) 2005-2016 Laurent Destailleur <eldy@users.sourceforge.net>
|
|
* Copyright (C) 2005-2016 Regis Houssin <regis.houssin@inodbox.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
* or see https://www.gnu.org/
|
|
*/
|
|
|
|
/**
|
|
* \file htdocs/viewimage.php
|
|
* \brief Wrapper to show images into Dolibarr screens.
|
|
* \remarks Call to wrapper is :
|
|
* DOL_URL_ROOT.'/viewimage.php?modulepart=diroffile&file=relativepathofofile&cache=0
|
|
* DOL_URL_ROOT.'/viewimage.php?hashp=sharekey
|
|
*/
|
|
|
|
define('MAIN_SECURITY_FORCECSP', "default-src: 'none'");
|
|
|
|
//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER','1'); // Not disabled cause need to load personalized language
|
|
//if (! defined('NOREQUIREDB')) define('NOREQUIREDB','1'); // Not disabled cause need to load personalized language
|
|
if (!defined('NOREQUIRESOC')) {
|
|
define('NOREQUIRESOC', '1');
|
|
}
|
|
if (!defined('NOREQUIRETRAN')) {
|
|
define('NOREQUIRETRAN', '1');
|
|
}
|
|
if (!defined('NOCSRFCHECK')) {
|
|
define('NOCSRFCHECK', '1');
|
|
}
|
|
if (!defined('NOTOKENRENEWAL')) {
|
|
define('NOTOKENRENEWAL', '1');
|
|
}
|
|
if (!defined('NOREQUIREMENU')) {
|
|
define('NOREQUIREMENU', '1');
|
|
}
|
|
if (!defined('NOREQUIREHTML')) {
|
|
define('NOREQUIREHTML', '1');
|
|
}
|
|
if (!defined('NOREQUIREAJAX')) {
|
|
define('NOREQUIREAJAX', '1');
|
|
}
|
|
|
|
// Some value of modulepart can be used to get resources that are public so no login are required.
|
|
// Note that only directory logo is free to access without login.
|
|
$needlogin = 1;
|
|
if (isset($_GET["modulepart"])) {
|
|
// Some value of modulepart can be used to get resources that are public so no login are required.
|
|
|
|
// For logo of company
|
|
if ($_GET["modulepart"] == 'mycompany' && preg_match('/^\/?logos\//', $_GET['file'])) {
|
|
$needlogin = 0;
|
|
}
|
|
// For barcode live generation
|
|
if ($_GET["modulepart"] == 'barcode') {
|
|
$needlogin = 0;
|
|
}
|
|
// Medias files
|
|
if ($_GET["modulepart"] == 'medias') {
|
|
$needlogin = 0;
|
|
}
|
|
// Common files (files into /public/theme/common)
|
|
if ($_GET["modulepart"] == 'common') {
|
|
$needlogin = 0;
|
|
}
|
|
// User photo when user has made its profile public (for virtual credi card)
|
|
if ($_GET["modulepart"] == 'userphotopublic') {
|
|
$needlogin = 0;
|
|
}
|
|
// Used by TakePOS Auto Order
|
|
if ($_GET["modulepart"] == 'product' && isset($_GET["publictakepos"])) {
|
|
$needlogin = 0;
|
|
}
|
|
}
|
|
// For direct external download link, we don't need to load/check we are into a login session
|
|
if (isset($_GET["hashp"])) {
|
|
$needlogin = 0;
|
|
}
|
|
// If nologin required
|
|
if (!$needlogin) {
|
|
if (!defined("NOLOGIN")) {
|
|
define("NOLOGIN", 1);
|
|
}
|
|
if (!defined("NOCSRFCHECK")) {
|
|
define("NOCSRFCHECK", 1); // We accept to go on this page from external web site.
|
|
}
|
|
if (!defined("NOIPCHECK")) {
|
|
define("NOIPCHECK", 1); // Do not check IP defined into conf $dolibarr_main_restrict_ip
|
|
}
|
|
}
|
|
|
|
// For multicompany
|
|
$entity = (!empty($_GET['entity']) ? (int) $_GET['entity'] : (!empty($_POST['entity']) ? (int) $_POST['entity'] : 1));
|
|
if (is_numeric($entity)) {
|
|
define("DOLENTITY", $entity);
|
|
}
|
|
|
|
/**
|
|
* Header empty
|
|
*
|
|
* @ignore
|
|
* @return void
|
|
*/
|
|
function llxHeader()
|
|
{
|
|
}
|
|
/**
|
|
* Footer empty
|
|
*
|
|
* @ignore
|
|
* @return void
|
|
*/
|
|
function llxFooter()
|
|
{
|
|
}
|
|
|
|
require 'main.inc.php'; // Load $user and permissions
|
|
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
|
|
|
|
$action = GETPOST('action', 'aZ09');
|
|
$original_file = GETPOST('file', 'alphanohtml'); // Do not use urldecode here ($_GET are already decoded by PHP).
|
|
$hashp = GETPOST('hashp', 'aZ09', 1); // Must be read only by GET
|
|
$modulepart = GETPOST('modulepart', 'alpha', 1); // Must be read only by GET
|
|
$urlsource = GETPOST('urlsource', 'alpha');
|
|
$entity = (GETPOST('entity', 'int') ? GETPOST('entity', 'int') : $conf->entity);
|
|
|
|
// Security check
|
|
if (empty($modulepart) && empty($hashp)) {
|
|
httponly_accessforbidden('Bad link. Bad value for parameter modulepart', 400);
|
|
}
|
|
if (empty($original_file) && empty($hashp) && $modulepart != 'barcode') {
|
|
httponly_accessforbidden('Bad link. Missing identification to find file (param file or hashp)', 400);
|
|
}
|
|
if ($modulepart == 'fckeditor') {
|
|
$modulepart = 'medias'; // For backward compatibility
|
|
}
|
|
|
|
|
|
/*
|
|
* Actions
|
|
*/
|
|
|
|
// None
|
|
|
|
|
|
|
|
/*
|
|
* View
|
|
*/
|
|
|
|
if (GETPOST("cache", 'alpha')) {
|
|
// Important: Following code is to avoid page request by browser and PHP CPU at each Dolibarr page access.
|
|
// Add param cache=abcdef
|
|
if (empty($dolibarr_nocache)) {
|
|
header('Cache-Control: max-age=3600, public, must-revalidate');
|
|
header('Pragma: cache'); // This is to avoid to have Pragma: no-cache set by proxy or web server
|
|
header('Expires: '.gmdate('D, d M Y H:i:s', time() + 3600).' GMT'); // This is to avoid to have Expires set by proxy or web server
|
|
//header('Expires: '.strtotime('+1 hour');
|
|
} else {
|
|
header('Cache-Control: no-cache');
|
|
}
|
|
//print $dolibarr_nocache; exit;
|
|
}
|
|
|
|
// If we have a hash public (hashp), we guess the original_file.
|
|
if (!empty($hashp)) {
|
|
include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
|
|
$ecmfile = new EcmFiles($db);
|
|
$result = $ecmfile->fetch(0, '', '', '', $hashp);
|
|
if ($result > 0) {
|
|
$tmp = explode('/', $ecmfile->filepath, 2); // $ecmfile->filepath is relative to document directory
|
|
// filepath can be 'users/X' or 'X/propale/PR11111'
|
|
if (is_numeric($tmp[0])) { // If first tmp is numeric, it is subdir of company for multicompany, we take next part.
|
|
$tmp = explode('/', $tmp[1], 2);
|
|
}
|
|
$moduleparttocheck = $tmp[0]; // moduleparttocheck is first part of path
|
|
|
|
if ($modulepart) { // Not required, so often not defined, for link using public hashp parameter.
|
|
if ($moduleparttocheck == $modulepart) {
|
|
// We remove first level of directory
|
|
$original_file = (($tmp[1] ? $tmp[1].'/' : '').$ecmfile->filename); // this is relative to module dir
|
|
//var_dump($original_file); exit;
|
|
} else {
|
|
httponly_accessforbidden('Bad link. File is from another module part.', 403);
|
|
}
|
|
} else {
|
|
$modulepart = $moduleparttocheck;
|
|
$original_file = (($tmp[1] ? $tmp[1].'/' : '').$ecmfile->filename); // this is relative to module dir
|
|
}
|
|
} else {
|
|
httponly_accessforbidden("ErrorFileNotFoundWithSharedLink", 403, 1);
|
|
}
|
|
}
|
|
|
|
// Define mime type
|
|
$type = 'application/octet-stream';
|
|
if (GETPOST('type', 'alpha')) {
|
|
$type = GETPOST('type', 'alpha');
|
|
} else {
|
|
$type = dol_mimetype($original_file);
|
|
}
|
|
|
|
// Security: This wrapper is for images. We do not allow type/html
|
|
if (preg_match('/html/i', $type)) {
|
|
httponly_accessforbidden('Error: Using the image wrapper to output a file with a mime type HTML is not possible.');
|
|
}
|
|
// Security: This wrapper is for images. We do not allow files ending with .noexe
|
|
if (preg_match('/\.noexe$/i', $original_file)) {
|
|
httponly_accessforbidden('Error: Using the image wrapper to output a file ending with .noexe is not allowed.');
|
|
}
|
|
|
|
// Security: Delete string ../ or ..\ into $original_file
|
|
$original_file = preg_replace('/\.\.+/', '..', $original_file); // Replace '... or more' with '..'
|
|
$original_file = str_replace('../', '/', $original_file);
|
|
$original_file = str_replace('..\\', '/', $original_file);
|
|
|
|
// Find the subdirectory name as the reference
|
|
$refname = basename(dirname($original_file)."/");
|
|
if ($refname == 'thumbs') {
|
|
// If we get the thumbs directory, we must go one step higher. For example original_file='10/thumbs/myfile_small.jpg' -> refname='10'
|
|
$refname = basename(dirname(dirname($original_file))."/");
|
|
}
|
|
|
|
// Check that file is allowed for view with viewimage.php
|
|
if (!empty($original_file) && !dolIsAllowedForPreview($original_file)) {
|
|
httponly_accessforbidden('This file extension is not qualified for preview', 403);
|
|
}
|
|
|
|
// Security check
|
|
if (empty($modulepart)) {
|
|
httponly_accessforbidden('Bad value for parameter modulepart', 400);
|
|
}
|
|
|
|
// When logged in a different entity, medias cannot be accessed because $conf->$module->multidir_output
|
|
// is not set on the requested entity, but they are public documents, so reset entity
|
|
if ($modulepart === 'medias' && $entity != $conf->entity) {
|
|
$conf->entity = $entity;
|
|
$conf->setValues($db);
|
|
}
|
|
|
|
$check_access = dol_check_secure_access_document($modulepart, $original_file, $entity, $user, $refname);
|
|
$accessallowed = $check_access['accessallowed'];
|
|
$sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals'];
|
|
$fullpath_original_file = $check_access['original_file']; // $fullpath_original_file is now a full path name
|
|
|
|
if (!empty($hashp)) {
|
|
$accessallowed = 1; // When using hashp, link is public so we force $accessallowed
|
|
$sqlprotectagainstexternals = '';
|
|
} elseif (GETPOSTINT("publictakepos")) {
|
|
if (getDolGlobalString('TAKEPOS_AUTO_ORDER') && in_array($modulepart, array('product', 'category'))) {
|
|
$accessallowed = 1; // When TakePOS Public Auto Order is enabled, we accept to see all images of product and categories with no login
|
|
// TODO Replace this with a call of getPublicImageOfObject like used by website so
|
|
// only shared images are visible
|
|
}
|
|
} else {
|
|
// Basic protection (against external users only)
|
|
if ($user->socid > 0) {
|
|
if ($sqlprotectagainstexternals) {
|
|
$resql = $db->query($sqlprotectagainstexternals);
|
|
if ($resql) {
|
|
$num = $db->num_rows($resql);
|
|
$i = 0;
|
|
while ($i < $num) {
|
|
$obj = $db->fetch_object($resql);
|
|
if ($user->socid != $obj->fk_soc) {
|
|
$accessallowed = 0;
|
|
break;
|
|
}
|
|
$i++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Security:
|
|
// Limit access if permissions are wrong
|
|
if (!$accessallowed) {
|
|
accessforbidden();
|
|
}
|
|
|
|
// Security:
|
|
// On interdit les remontees de repertoire ainsi que les pipe dans les noms de fichiers.
|
|
if (preg_match('/\.\./', $fullpath_original_file) || preg_match('/[<>|]/', $fullpath_original_file)) {
|
|
dol_syslog("Refused to deliver file ".$fullpath_original_file);
|
|
print "ErrorFileNameInvalid: ".dol_escape_htmltag($original_file);
|
|
exit;
|
|
}
|
|
|
|
|
|
|
|
if ($modulepart == 'barcode') {
|
|
$generator = GETPOST("generator", "aZ09");
|
|
$encoding = GETPOST("encoding", "aZ09");
|
|
$readable = GETPOST("readable", 'aZ09') ? GETPOST("readable", "aZ09") : "Y";
|
|
if (in_array($encoding, array('EAN8', 'EAN13'))) {
|
|
$code = GETPOST("code", 'alphanohtml');
|
|
} else {
|
|
$code = GETPOST("code", 'restricthtml'); // This can be rich content (qrcode, datamatrix, ...)
|
|
}
|
|
|
|
if (empty($generator) || empty($encoding)) {
|
|
print 'Error: Parameter "generator" or "encoding" not defined';
|
|
exit;
|
|
}
|
|
|
|
$dirbarcode = array_merge(array("/core/modules/barcode/doc/"), $conf->modules_parts['barcode']);
|
|
|
|
$result = 0;
|
|
|
|
foreach ($dirbarcode as $reldir) {
|
|
$dir = dol_buildpath($reldir, 0);
|
|
$newdir = dol_osencode($dir);
|
|
|
|
// Check if directory exists (we do not use dol_is_dir to avoid loading files.lib.php)
|
|
if (!is_dir($newdir)) {
|
|
continue;
|
|
}
|
|
|
|
$result = @include_once $newdir.$generator.'.modules.php';
|
|
if ($result) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Load barcode class
|
|
$classname = "mod".ucfirst($generator);
|
|
$module = new $classname($db);
|
|
if ($module->encodingIsSupported($encoding)) {
|
|
$result = $module->buildBarCode($code, $encoding, $readable);
|
|
}
|
|
} else {
|
|
// Open and return file
|
|
clearstatcache();
|
|
|
|
$filename = basename($fullpath_original_file);
|
|
|
|
// Output files on browser
|
|
dol_syslog("viewimage.php return file $fullpath_original_file filename=$filename content-type=$type");
|
|
|
|
if (!dol_is_file($fullpath_original_file) && !GETPOSTINT("noalt", 1)) {
|
|
// This test is to replace error images with a nice "notfound image" when image is not available (for example when thumbs not yet generated).
|
|
$fullpath_original_file = DOL_DOCUMENT_ROOT.'/public/theme/common/nophoto.png';
|
|
/*$error='Error: File '.$_GET["file"].' does not exists or filesystems permissions are not allowed';
|
|
print $error;
|
|
exit;*/
|
|
}
|
|
|
|
// Permissions are ok and file found, so we return it
|
|
if ($type) {
|
|
top_httphead($type);
|
|
header('Content-Disposition: inline; filename="'.basename($fullpath_original_file).'"');
|
|
} else {
|
|
top_httphead('image/png');
|
|
header('Content-Disposition: inline; filename="'.basename($fullpath_original_file).'"');
|
|
}
|
|
|
|
$fullpath_original_file_osencoded = dol_osencode($fullpath_original_file);
|
|
|
|
readfile($fullpath_original_file_osencoded);
|
|
}
|
|
|
|
|
|
if (is_object($db)) {
|
|
$db->close();
|
|
}
|