From 96efe43e3cbcc8c8f7a94b5187be927cbc679068 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 21 Sep 2017 12:48:07 +0200 Subject: [PATCH] NEW Provide a way to download a file from a public URL. --- htdocs/document.php | 37 ++++++++++++++++++++++++++--- htdocs/ecm/class/ecmfiles.class.php | 15 +++++++++--- htdocs/ecm/docfile.php | 30 ++++++++++++++--------- 3 files changed, 65 insertions(+), 17 deletions(-) diff --git a/htdocs/document.php b/htdocs/document.php index d35021005e6..c09441ea0ed 100644 --- a/htdocs/document.php +++ b/htdocs/document.php @@ -59,24 +59,28 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; $encoding = ''; $action=GETPOST('action','alpha'); -$original_file=GETPOST('file','alpha'); // Do not use urldecode here ($_GET are already decoded by PHP). +$original_file=GETPOST('file','alpha'); // Do not use urldecode here ($_GET are already decoded by PHP). +$hashn=GETPOST('hashn','aZ09'); +$hashc=GETPOST('hashc','aZ09'); $modulepart=GETPOST('modulepart','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)) accessforbidden('Bad link. Bad value for parameter modulepart',0,0,1); +if (empty($original_file) && empty($hashn) && empty($hashc)) accessforbidden('Bad link. Missing identification to find file (original_file, hasn or hashc)',0,0,1); if ($modulepart == 'fckeditor') $modulepart='medias'; // For backward compatibility $socid=0; if ($user->societe_id > 0) $socid = $user->societe_id; // For some module part, dir may be privates -if (in_array($modulepart,array('facture_paiement','unpaid'))) +if (in_array($modulepart, array('facture_paiement','unpaid'))) { if (! $user->rights->societe->client->voir || $socid) $original_file='private/'.$user->id.'/'.$original_file; // If user has no permission to see all, output dir is specific to user } + /* * Action */ @@ -99,6 +103,33 @@ if (preg_match('/\.(html|htm)$/i',$original_file)) $attachment = false; if (isset($_GET["attachment"])) $attachment = GETPOST("attachment",'alpha')?true:false; if (! empty($conf->global->MAIN_DISABLE_FORCE_SAVEAS)) $attachment=false; +// If we have a hash (hashc or hashn), we guess the original_file. Note: using hashn is not reliable. +if (! empty($hashn) || ! empty($hashc)) +{ + include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php'; + $ecmfile=new EcmFiles($db); + $result = $ecmfile->fetch(0, $hashn, '', $hashc); + if ($result > 0) + { + $tmp = explode('/', $ecmfile->filepath, 2); // $ecmfile->filepatch is relative to document directory + $moduleparttocheck = $tmp[0]; + if ($moduleparttocheck == $modulepart) + { + $original_file = (($tmp[1]?$tmp[1].'/':'').$ecmfile->filename); // this is relative to module dir + //var_dump($original_file); exit; + } + else + { + accessforbidden('Bad link. File owns to another module part.',0,0,1); + } + } + else + { + accessforbidden('Bad link. File was not found or removed recently.',0,0,1); + } +} + + // Security: Delete string ../ into $original_file $original_file = str_replace("../","/", $original_file); diff --git a/htdocs/ecm/class/ecmfiles.class.php b/htdocs/ecm/class/ecmfiles.class.php index abe5c403462..77fa294aeed 100644 --- a/htdocs/ecm/class/ecmfiles.class.php +++ b/htdocs/ecm/class/ecmfiles.class.php @@ -157,6 +157,7 @@ class EcmFiles //extends CommonObject // Insert request $sql = 'INSERT INTO ' . MAIN_DB_PREFIX . $this->table_element . '('; + $sql.= 'ref,'; $sql.= 'label,'; $sql.= 'entity,'; $sql.= 'filename,'; @@ -174,6 +175,7 @@ class EcmFiles //extends CommonObject $sql.= 'fk_user_m,'; $sql.= 'acl'; $sql .= ') VALUES ('; + $sql .= " '".dol_hash($this->filepath.'/'.$this->filename, 3)."', "; $sql .= ' '.(! isset($this->label)?'NULL':"'".$this->db->escape($this->label)."'").','; $sql .= ' '.(! isset($this->entity)?$conf->entity:$this->entity).','; $sql .= ' '.(! isset($this->filename)?'NULL':"'".$this->db->escape($this->filename)."'").','; @@ -232,11 +234,12 @@ class EcmFiles //extends CommonObject * Load object in memory from the database * * @param int $id Id object - * @param string $ref Not used yet. Will contains a hash id from filename+filepath + * @param string $ref Hash of file name (filename+filepath). Not always defined on some version. * @param string $relativepath Relative path of file from document directory. Example: path/path2/file + * @param string $hashoffile Hash of file content. Take the first one found if same file is at different places. This hash will also change if file content is changed. * @return int <0 if KO, 0 if not found, >0 if OK */ - public function fetch($id, $ref = null, $relativepath = '') + public function fetch($id, $ref = '', $relativepath = '', $hashoffile='') { dol_syslog(__METHOD__, LOG_DEBUG); @@ -268,11 +271,16 @@ class EcmFiles //extends CommonObject if ($relativepath) { $sql .= " AND t.filepath = '" . $this->db->escape(dirname($relativepath)) . "' AND t.filename = '".$this->db->escape(basename($relativepath))."'"; } - elseif (null !== $ref) { + elseif (! empty($ref)) { $sql .= " AND t.ref = '".$this->db->escape($ref)."'"; + } + elseif (! empty($hashoffile)) { + $sql .= " AND t.label = '".$this->db->escape($hashoffile)."'"; } else { $sql .= ' AND t.rowid = ' . $id; } + $this->db->plimit(1); + $this->db->order('t.rowid', 'ASC'); // When we search on hash of content, we take the first one. $resql = $this->db->query($sql); if ($resql) { @@ -484,6 +492,7 @@ class EcmFiles //extends CommonObject // Update request $sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element . ' SET'; + $sql .= ' ref = '.dol_hash($this->filepath.'/'.$this->filename, 3); $sql .= ' label = '.(isset($this->label)?"'".$this->db->escape($this->label)."'":"null").','; $sql .= ' entity = '.(isset($this->entity)?$this->entity:$conf->entity).','; $sql .= ' filename = '.(isset($this->filename)?"'".$this->db->escape($this->filename)."'":"null").','; diff --git a/htdocs/ecm/docfile.php b/htdocs/ecm/docfile.php index 045c3ebda8b..aa708a85f24 100644 --- a/htdocs/ecm/docfile.php +++ b/htdocs/ecm/docfile.php @@ -287,17 +287,25 @@ print ' '.$langs->trans("Download").''; print ''; print ''.$langs->trans("DirectDownloadLink").''; -$modulepart='ecm'; -$forcedownload=1; -$rellink='/document.php?modulepart='.$modulepart; -if ($forcedownload) $rellink.='&attachment=1'; -if (! empty($object->entity)) $rellink.='&entity='.$object->entity; -$rellink.='&file='.urlencode($filepath); -$fulllink=$urlwithroot.$rellink; -// TODO -//print img_picto('','object_globe.png').' '; -//print ''; -//print ' '.$langs->trans("Download").''; +if (! empty($ecmfile->ref) || ! empty($ecmfile->label)) +{ + $modulepart='ecm'; + $forcedownload=1; + $rellink='/document.php?modulepart='.$modulepart; + if ($forcedownload) $rellink.='&attachment=1'; + if (! empty($object->entity)) $rellink.='&entity='.$object->entity; + //$rellink.='&file='.urlencode($filepath); // No need of name of file for public link, we will use the hash + $fulllink=$urlwithroot.$rellink; + if (! empty($ecmfile->ref)) $fulllink.='&hashn='.$ecmfile->ref; // Hash of file path + elseif (! empty($ecmfile->label)) $fulllink.='&hashc='.$ecmfile->label; // Hash of file content + print img_picto('','object_globe.png').' '; + print ''; + print ' '.$langs->trans("Download").''; +} +else +{ + print img_warning().' '.$langs->trans("FileNotYetIndexedInDatabase"); +} print ''; print '';