NEW Can share any file from the "Document" tab.

This commit is contained in:
Laurent Destailleur 2018-02-13 13:55:36 +01:00
parent 3b9eaf6a5e
commit 1a4aa89489
6 changed files with 227 additions and 71 deletions

View File

@ -182,37 +182,70 @@ elseif ($action == 'renamefile' && GETPOST('renamefilesave','alpha'))
$filenamefrom=dol_sanitizeFileName(GETPOST('renamefilefrom','alpha'), '_', 0); // Do not remove accents
$filenameto=dol_sanitizeFileName(GETPOST('renamefileto','alpha'), '_', 0); // Do not remove accents
// Security:
// Disallow file with some extensions. We rename them.
// Because if we put the documents directory into a directory inside web root (very bad), this allows to execute on demand arbitrary code.
if (preg_match('/\.htm|\.html|\.php|\.pl|\.cgi$/i',$filenameto) && empty($conf->global->MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED))
if ($filenamefrom != $filenameto)
{
$filenameto.= '.noexe';
}
// Security:
// Disallow file with some extensions. We rename them.
// Because if we put the documents directory into a directory inside web root (very bad), this allows to execute on demand arbitrary code.
if (preg_match('/\.htm|\.html|\.php|\.pl|\.cgi$/i',$filenameto) && empty($conf->global->MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED))
{
$filenameto.= '.noexe';
}
if ($filenamefrom && $filenameto)
{
$srcpath = $upload_dir.'/'.$filenamefrom;
$destpath = $upload_dir.'/'.$filenameto;
if ($filenamefrom && $filenameto)
{
$srcpath = $upload_dir.'/'.$filenamefrom;
$destpath = $upload_dir.'/'.$filenameto;
$result = dol_move($srcpath, $destpath);
if ($result)
{
if ($object->id)
{
$object->addThumbs($destpath);
}
$result = dol_move($srcpath, $destpath);
if ($result)
{
if ($object->id)
{
$object->addThumbs($destpath);
}
// TODO Add revert function of addThumbs to remove for old name
//$object->delThumbs($srcpath);
// TODO Add revert function of addThumbs to remove for old name
//$object->delThumbs($srcpath);
setEventMessages($langs->trans("FileRenamed"), null);
}
else
{
$langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
setEventMessages($langs->trans("ErrorFailToRenameFile", $filenamefrom, $filenameto), null, 'errors');
}
setEventMessages($langs->trans("FileRenamed"), null);
}
else
{
$langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
setEventMessages($langs->trans("ErrorFailToRenameFile", $filenamefrom, $filenameto), null, 'errors');
}
}
}
}
// Update properties in ECM table
if (GETPOST('ecmfileid', 'int') > 0)
{
$shareenabled = GETPOST('shareenabled', 'alpha');
include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
$ecmfile=new EcmFiles($db);
$result = $ecmfile->fetch(GETPOST('ecmfileid', 'int'));
if ($result > 0)
{
if ($shareenabled)
{
if (empty($ecmfile->share))
{
require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
$ecmfile->share = getRandomPassword(true);
}
}
else
{
$ecmfile->share = '';
}
$result = $ecmfile->update($user);
if ($result < 0)
{
setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings');
}
}
}
}

View File

@ -938,7 +938,7 @@ class FormFile
* @param string $url Full url to use for click links ('' = autodetect)
* @param int $showrelpart 0=Show only filename (default), 1=Show first level 1 dir
* @param int $permtoeditline Permission to edit document line (You must provide a value, -1 is deprecated and must not be used any more)
* @param string $upload_dir Full path directory so we can know dir relative to MAIN_DATA_ROOT. Fill this if you want to complete file data with database indexes.
* @param string $upload_dir Full path directory so we can know dir relative to MAIN_DATA_ROOT. Fill this to complete file data with database indexes.
* @param string $sortfield Sort field ('name', 'size', 'position', ...)
* @param string $sortorder Sort order ('ASC' or 'DESC')
* @param int $disablemove 1=Disable move button, 0=Position move is possible.
@ -951,6 +951,7 @@ class FormFile
global $user, $conf, $langs, $hookmanager;
global $bc,$bcdd;
global $sortfield, $sortorder, $maxheightmini;
global $dolibarr_main_url_root;
// Define relative path used to store the file
if (empty($relativepath))
@ -1038,6 +1039,7 @@ class FormFile
print '<td></td>';
if (empty($useinecm)) print '<td></td>';
print '<td></td>';
print '<td></td>';
if (! $disablemove) print '<td></td>';
print "</tr>\n";
}
@ -1047,7 +1049,8 @@ class FormFile
print_liste_field_titre('Documents2',$url,"name","",$param,'align="left"',$sortfield,$sortorder);
print_liste_field_titre('Size',$url,"size","",$param,'align="right"',$sortfield,$sortorder);
print_liste_field_titre('Date',$url,"date","",$param,'align="center"',$sortfield,$sortorder);
if (empty($useinecm)) print_liste_field_titre('',$url,"","",$param,'align="center"');
if (empty($useinecm)) print_liste_field_titre('',$url,"","",$param,'align="center"'); // Preview
print_liste_field_titre('');
print_liste_field_titre('');
if (! $disablemove) print_liste_field_titre('');
print "</tr>\n";
@ -1063,7 +1066,6 @@ class FormFile
//var_dump($sortfield);
$filearray=dol_sort_array($filearray, $sortfield, $sortorder);
}
//var_dump($filearray);
}
$nboffiles=count($filearray);
@ -1146,6 +1148,48 @@ class FormFile
else print '&nbsp;';
print '</td>';
}
// Hash of file (only if we are in a mode where a scan of dir were done and we have id of file in ECM table)
print '<td align="center">';
if ($relativedir && $filearray[$key]['rowid'] > 0)
{
if ($editline)
{
print $langs->trans("FileSharedViaALink").' ';
print '<input class="inline-block" type="checkbox" name="shareenabled"'.($file['share']?' checked="checked"':'').' /> ';
}
else
{
if ($file['share'])
{
// Define $urlwithroot
$urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($dolibarr_main_url_root));
$urlwithroot=$urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
//$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
//print '<span class="opacitymedium">'.$langs->trans("Hash").' : '.$file['share'].'</span>';
$forcedownload=0;
$paramlink='';
if (! empty($file['share'])) $paramlink.=($paramlink?'&':'').'hashp='.$file['share']; // Hash for public share
if ($forcedownload) $paramlink.=($paramlink?'&':'').'attachment=1';
$fulllink=$urlwithroot.'/document.php'.($paramlink?'?'.$paramlink:'');
//if (! empty($object->ref)) $fulllink.='&hashn='.$object->ref; // Hash of file path
//elseif (! empty($object->label)) $fulllink.='&hashc='.$object->label; // Hash of file content
print img_picto($langs->trans("FileSharedViaALink"),'object_globe.png').' ';
print '<input type="text" class="quatrevingtpercent" id="downloadlink" name="downloadexternallink" value="'.dol_escape_htmltag($fulllink).'">';
//print ' <a href="'.$fulllink.'">'.$langs->trans("Download").'</a>'; // No target here
}
else
{
//print '<span class="opacitymedium">'.$langs->trans("FileNotShared").'</span>';
}
}
}
print '</td>';
// Actions buttons
if (! $editline)
{
// Delete or view link
@ -1215,6 +1259,7 @@ class FormFile
else
{
print '<td class="right">';
print '<input type="hidden" name="ecmfileid" value="'.$filearray[$key]['rowid'].'">';
print '<input type="submit" class="button" name="renamefilesave" value="'.dol_escape_htmltag($langs->trans("Save")).'">';
print '<input type="submit" class="button" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'">';
print '</td>';
@ -1227,9 +1272,9 @@ class FormFile
}
if ($nboffiles == 0)
{
$colspan=(empty($useinecm)?'5':'5');
if (empty($disablemove)) $colspan++;
print '<tr '.$bc[false].'><td colspan="'.$colspan.'" class="opacitymedium">';
$colspan=(empty($useinecm)?'6':'6');
if (empty($disablemove)) $colspan++; // 6 columns or 7
print '<tr class="oddeven"><td colspan="'.$colspan.'" class="opacitymedium">';
if (empty($textifempty)) print $langs->trans("NoFileFound");
else print $textifempty;
print '</td></tr>';
@ -1249,6 +1294,8 @@ class FormFile
print '</form>';
}
print ajax_autoselect('downloadlink');
return $nboffiles;
}
}

View File

@ -225,7 +225,8 @@ function dol_dir_list_in_database($path, $filter="", $excludefilter=null, $sortc
{
global $conf, $db;
$sql=" SELECT rowid, label, entity, filename, filepath, fullpath_orig, keywords, cover, gen_or_uploaded, extraparams, date_c, date_m, fk_user_c, fk_user_m, acl, position";
$sql =" SELECT rowid, label, entity, filename, filepath, fullpath_orig, keywords, cover, gen_or_uploaded, extraparams, date_c, date_m, fk_user_c, fk_user_m,";
$sql.=" acl, position, share";
if ($mode) $sql.=", description";
$sql.=" FROM ".MAIN_DB_PREFIX."ecm_files";
$sql.=" WHERE filepath = '".$db->escape($path)."'";
@ -258,7 +259,8 @@ function dol_dir_list_in_database($path, $filter="", $excludefilter=null, $sortc
"keywords" => $obj->keywords,
"cover" => $obj->cover,
"position" => (int) $obj->position,
"acl" => $obj->acl
"acl" => $obj->acl,
"share" => $obj->share
);
}
$i++;
@ -318,6 +320,7 @@ function completeFileArrayWithDatabaseInfo(&$filearray, $relativedir)
$filearray[$key]['acl']=$filearrayindatabase[$key2]['acl'];
$filearray[$key]['rowid']=$filearrayindatabase[$key2]['rowid'];
$filearray[$key]['label']=$filearrayindatabase[$key2]['label'];
$filearray[$key]['share']=$filearrayindatabase[$key2]['share'];
$found=1;
break;
}

View File

@ -25,9 +25,9 @@
* \file htdocs/document.php
* \brief Wrapper to download data files
* \remarks Call of this wrapper is made with URL:
* document.php?modulepart=repfichierconcerne&file=relativepathoffile
* document.php?modulepart=logs&file=dolibarr.log
* document.php?modulepart=logs&hashp=sharekey
* DOL_URL_ROOT.'/document.php?modulepart=repfichierconcerne&file=relativepathoffile'
* DOL_URL_ROOT.'/document.php?modulepart=logs&file=dolibarr.log'
* DOL_URL_ROOT.'/document.php?hashp=sharekey'
*/
//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER','1'); // Not disabled cause need to load personalized language
@ -36,9 +36,9 @@
//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');
if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU','1');
if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML','1');
if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX','1');
//if (! defined('NOREQUIREHOOK')) define('NOREQUIREHOOK','1'); // Disable "main.inc.php" hooks
// For bittorent link, we don't need to load/check we are into a login session
if (isset($_GET["modulepart"]) && $_GET["modulepart"] == 'bittorrent' && ! defined("NOLOGIN"))
@ -58,9 +58,6 @@ if ((isset($_GET["modulepart"]) && $_GET["modulepart"] == 'medias') && ! defined
define("NOLOGIN",1);
define("NOCSRFCHECK",1); // We accept to go on this page from external web site.
}
if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU','1');
if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML','1');
if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX','1');
/**
* Header empty
@ -75,7 +72,6 @@ function llxHeader() { }
*/
function llxFooter() { }
require 'main.inc.php'; // Load $user and permissions
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
@ -103,21 +99,17 @@ if (in_array($modulepart, array('facture_paiement','unpaid')))
/*
* Action
* Actions
*/
// None
/*
* View
*/
// Define mime type
$type = 'application/octet-stream';
if (GETPOST('type','alpha')) $type=GETPOST('type','alpha');
else $type=dol_mimetype($original_file);
// Define attachment (attachment=true to force choice popup 'open'/'save as')
$attachment = true;
if (preg_match('/\.(html|htm)$/i',$original_file)) $attachment = false;
@ -160,6 +152,10 @@ if (! empty($hashp))
}
}
// Define mime type
$type = 'application/octet-stream';
if (GETPOST('type','alpha')) $type=GETPOST('type','alpha');
else $type=dol_mimetype($original_file);
// Security: Delete string ../ into $original_file
$original_file = str_replace("../","/", $original_file);
@ -252,9 +248,6 @@ header('Content-Length: ' . dol_filesize($fullpath_original_file));
header('Cache-Control: Public, must-revalidate');
header('Pragma: public');
//ob_clean();
//flush();
readfile($fullpath_original_file_osencoded);
if (is_object($db)) $db->close();

View File

@ -341,13 +341,9 @@ if (! empty($object->share))
{
if ($action != 'edit')
{
$modulepart='ecm';
$forcedownload=0;
$paramlink='';
//if (! empty($modulepart)) $paramlink.=($paramlink?'&':'').'modulepart='.$modulepart; // For sharing with hash (so public files), modulepart is not required.
//if (! empty($object->entity)) $paramlink.='&entity='.$object->entity; // For sharing with hash (so public files), entity is not required.
//$paramlink.=($paramlink?'&':'').'file='.urlencode($filepath); // No need of name of file for public link, we will use the hash
if (! empty($object->share)) $paramlink.=($paramlink?'&':'').'hashp='.$object->share; // Hash for public share
if ($forcedownload) $paramlink.=($paramlink?'&':'').'attachment=1';

View File

@ -20,8 +20,10 @@
/**
* \file htdocs/viewimage.php
* \brief Wrapper to show images into Dolibarr screens
* \remarks Call to wrapper is '<img src="'.DOL_URL_ROOT.'/viewimage.php?modulepart=diroffile&file=relativepathofofile&cache=0">'
* \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
*/
//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER','1'); // Not disabled cause need to load personalized language
@ -35,7 +37,16 @@ if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML','1');
if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX','1');
if (! defined('NOREQUIREHOOK')) define('NOREQUIREHOOK','1'); // Disable "main.inc.php" hooks
// Some value of modulepart can be used to get resources that are public so no login are required.
if ((isset($_GET["modulepart"]) && ($_GET["modulepart"] == 'mycompany' || $_GET["modulepart"] == 'companylogo')) && ! defined("NOLOGIN")) define("NOLOGIN",'1');
if ((isset($_GET["modulepart"]) && ($_GET["modulepart"] == 'mycompany' || $_GET["modulepart"] == 'companylogo')) && ! defined("NOLOGIN"))
{
define("NOLOGIN",'1');
}
// For direct external download link, we don't need to load/check we are into a login session
if (isset($_GET["hashp"]) && ! defined("NOLOGIN"))
{
define("NOLOGIN",1);
}
// Some value of modulepart can be used to get resources that are public so no login are required.
if ((isset($_GET["modulepart"]) && $_GET["modulepart"] == 'medias') && ! defined("NOLOGIN"))
{
define("NOLOGIN",'1');
@ -57,18 +68,20 @@ function llxHeader() { }
*/
function llxFooter() { }
require 'main.inc.php';
require 'main.inc.php'; // Load $user and permissions
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
$action=GETPOST('action','alpha');
$original_file=GETPOST("file",'alpha');
$original_file=GETPOST('file','alpha'); // Do not use urldecode here ($_GET are already decoded by PHP).
$hashp=GETPOST('hashp','aZ09');
$modulepart=GETPOST('modulepart','alpha');
$urlsource=GETPOST("urlsource",'alpha');
$urlsource=GETPOST('urlsource','alpha');
$entity=GETPOST('entity','int')?GETPOST('entity','int'):$conf->entity;
// Security check
if (empty($modulepart)) accessforbidden('Bad value for parameter modulepart');
if (empty($modulepart) && empty($hashp)) accessforbidden('Bad link. Bad value for parameter modulepart',0,0,1);
if (empty($original_file) && empty($hashp)) accessforbidden('Bad link. Missing identification to find file (original_file or hashp)',0,0,1);
if ($modulepart == 'fckeditor') $modulepart='medias'; // For backward compatibility
@ -97,9 +110,45 @@ if (GETPOST("cache",'alpha'))
//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
$moduleparttocheck = $tmp[0];
if ($modulepart) // Not required for link using public hashp
{
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
{
accessforbidden('Bad link. File is from another module part.',0,0,1);
}
}
else
{
$modulepart = $moduleparttocheck;
$original_file = (($tmp[1]?$tmp[1].'/':'').$ecmfile->filename); // this is relative to module dir
}
}
else
{
$langs->load("errors");
accessforbidden($langs->trans("ErrorFileNotFoundWithSharedLink"),0,0,1);
}
}
// Define mime type
$type = 'application/octet-stream';
if (! empty($_GET["type"])) $type=$_GET["type"];
if (GETPOST('type','alpha')) $type=GETPOST('type','alpha');
else $type=dol_mimetype($original_file);
// Security: Delete string ../ into $original_file
@ -110,16 +159,49 @@ $refname=basename(dirname($original_file)."/");
// Security check
if (empty($modulepart)) accessforbidden('Bad value for parameter modulepart');
$check_access = dol_check_secure_access_document($modulepart,$original_file,$entity,$refname);
$check_access = dol_check_secure_access_document($modulepart, $original_file, $entity, $refname);
$accessallowed = $check_access['accessallowed'];
$sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals'];
$fullpath_original_file = $check_access['original_file'];
$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 = '';
}
else
{
// Basic protection (against external users only)
if ($user->societe_id > 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->societe_id != $obj->fk_soc)
{
$accessallowed=0;
break;
}
$i++;
}
}
}
}
}
// Security:
// Limit access if permissions are wrong
if (! $accessallowed)
{
accessforbidden();
accessforbidden();
}
// Security:
@ -128,7 +210,7 @@ if (preg_match('/\.\./',$fullpath_original_file) || preg_match('/[<>|]/',$fullpa
{
dol_syslog("Refused to deliver file ".$fullpath_original_file);
print "ErrorFileNameInvalid: ".$original_file;
exit;
exit;
}
@ -174,8 +256,10 @@ else // Open and return file
{
clearstatcache();
$filename = basename($fullpath_original_file);
// Output files on browser
dol_syslog("viewimage.php return file $fullpath_original_file content-type=$type");
dol_syslog("viewimage.php return file $fullpath_original_file filename=$filename content-type=$type");
// This test is to avoid error images when image is not available (for example thumbs).
if (! dol_is_file($fullpath_original_file) && empty($_GET["noalt"]))
@ -186,7 +270,7 @@ else // Open and return file
exit;*/
}
// Les drois sont ok et fichier trouve
// Permissions are ok and file found, so we return it
if ($type)
{
top_httphead($type);