dolibarr  19.0.0-dev
api_documents.class.php
1 <?php
2 /* Copyright (C) 2016 Xebax Christy <xebax@wanadoo.fr>
3  * Copyright (C) 2016 Laurent Destailleur <eldy@users.sourceforge.net>
4  * Copyright (C) 2016 Jean-François Ferry <jfefe@aternatik.fr>
5  * Copyright (C) 2023 Romain Neil <contact@romain-neil.fr>
6  *
7  * This program is free software you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <https://www.gnu.org/licenses/>.
19  */
20 
21 use Luracast\Restler\RestException;
22 use Luracast\Restler\Format\UploadFormat;
23 
24 require_once DOL_DOCUMENT_ROOT.'/main.inc.php';
25 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
26 
33 class Documents extends DolibarrApi
34 {
35 
39  public static $DOCUMENT_FIELDS = array(
40  'modulepart'
41  );
42 
46  public function __construct()
47  {
48  global $db;
49  $this->db = $db;
50  }
51 
52 
69  public function index($modulepart, $original_file = '')
70  {
71  global $conf, $langs;
72 
73  if (empty($modulepart)) {
74  throw new RestException(400, 'bad value for parameter modulepart');
75  }
76  if (empty($original_file)) {
77  throw new RestException(400, 'bad value for parameter original_file');
78  }
79 
80  //--- Finds and returns the document
81  $entity = $conf->entity;
82 
83  // Special cases that need to use get_exdir to get real dir of object
84  // If future, all object should use this to define path of documents.
85  /*
86  $tmpreldir = '';
87  if ($modulepart == 'supplier_invoice') {
88  $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
89  }
90 
91  $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref); */
92  $relativefile = $original_file;
93 
94  $check_access = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'read');
95  $accessallowed = $check_access['accessallowed'];
96  $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals'];
97  $original_file = $check_access['original_file'];
98 
99  if (preg_match('/\.\./', $original_file) || preg_match('/[<>|]/', $original_file)) {
100  throw new RestException(401);
101  }
102  if (!$accessallowed) {
103  throw new RestException(401);
104  }
105 
106  $filename = basename($original_file);
107  $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset
108 
109  if (!file_exists($original_file_osencoded)) {
110  dol_syslog("Try to download not found file ".$original_file_osencoded, LOG_WARNING);
111  throw new RestException(404, 'File not found');
112  }
113 
114  $file_content = file_get_contents($original_file_osencoded);
115  return array('filename'=>$filename, 'content-type' => dol_mimetype($filename), 'filesize'=>filesize($original_file), 'content'=>base64_encode($file_content), 'encoding'=>'base64');
116  }
117 
118 
140  public function builddoc($modulepart, $original_file = '', $doctemplate = '', $langcode = '')
141  {
142  global $conf, $langs;
143 
144  if (empty($modulepart)) {
145  throw new RestException(400, 'bad value for parameter modulepart');
146  }
147  if (empty($original_file)) {
148  throw new RestException(400, 'bad value for parameter original_file');
149  }
150 
151  $outputlangs = $langs;
152  if ($langcode && $langs->defaultlang != $langcode) {
153  $outputlangs = new Translate('', $conf);
154  $outputlangs->setDefaultLang($langcode);
155  }
156 
157  //--- Finds and returns the document
158  $entity = $conf->entity;
159 
160  // Special cases that need to use get_exdir to get real dir of object
161  // If future, all object should use this to define path of documents.
162  /*
163  $tmpreldir = '';
164  if ($modulepart == 'supplier_invoice') {
165  $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
166  }
167 
168  $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref); */
169  $relativefile = $original_file;
170 
171  $check_access = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'write');
172  $accessallowed = $check_access['accessallowed'];
173  $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals'];
174  $original_file = $check_access['original_file'];
175 
176  if (preg_match('/\.\./', $original_file) || preg_match('/[<>|]/', $original_file)) {
177  throw new RestException(401);
178  }
179  if (!$accessallowed) {
180  throw new RestException(401);
181  }
182 
183  // --- Generates the document
184  $hidedetails = empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS) ? 0 : 1;
185  $hidedesc = empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DESC) ? 0 : 1;
186  $hideref = empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_REF) ? 0 : 1;
187 
188  $templateused = '';
189 
190  if ($modulepart == 'facture' || $modulepart == 'invoice') {
191  require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
192  $this->invoice = new Facture($this->db);
193  $result = $this->invoice->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
194  if (!$result) {
195  throw new RestException(404, 'Invoice not found');
196  }
197 
198  $templateused = $doctemplate ? $doctemplate : $this->invoice->model_pdf;
199  $result = $this->invoice->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
200  if ($result <= 0) {
201  throw new RestException(500, 'Error generating document');
202  }
203  } elseif ($modulepart == 'facture_fournisseur' || $modulepart == 'invoice_supplier') {
204  require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.facture.class.php';
205  $this->supplier_invoice = new FactureFournisseur($this->db);
206  $result = $this->supplier_invoice->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
207  if (!$result) {
208  throw new RestException(404, 'Supplier invoice not found');
209  }
210 
211  $templateused = $doctemplate ? $doctemplate : $this->supplier_invoice->model_pdf;
212  $result = $this->supplier_invoice->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
213  if ($result < 0) {
214  throw new RestException(500, 'Error generating document');
215  }
216  } elseif ($modulepart == 'commande' || $modulepart == 'order') {
217  require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
218  $this->order = new Commande($this->db);
219  $result = $this->order->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
220  if (!$result) {
221  throw new RestException(404, 'Order not found');
222  }
223  $templateused = $doctemplate ? $doctemplate : $this->order->model_pdf;
224  $result = $this->order->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
225  if ($result <= 0) {
226  throw new RestException(500, 'Error generating document');
227  }
228  } elseif ($modulepart == 'propal' || $modulepart == 'proposal') {
229  require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
230  $this->propal = new Propal($this->db);
231  $result = $this->propal->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
232  if (!$result) {
233  throw new RestException(404, 'Proposal not found');
234  }
235  $templateused = $doctemplate ? $doctemplate : $this->propal->model_pdf;
236  $result = $this->propal->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
237  if ($result <= 0) {
238  throw new RestException(500, 'Error generating document');
239  }
240  } elseif ($modulepart == 'contrat' || $modulepart == 'contract') {
241  require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
242 
243  $this->contract = new Contrat($this->db);
244  $result = $this->contract->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
245 
246  if (!$result) {
247  throw new RestException(404, 'Contract not found');
248  }
249 
250  $templateused = $doctemplate ? $doctemplate : $this->contract->model_pdf;
251  $result = $this->contract->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
252 
253  if ($result <= 0) {
254  throw new RestException(500, 'Error generating document missing doctemplate parameter');
255  }
256  } else {
257  throw new RestException(403, 'Generation not available for this modulepart');
258  }
259 
260  $filename = basename($original_file);
261  $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset
262 
263  if (!file_exists($original_file_osencoded)) {
264  throw new RestException(404, 'File not found');
265  }
266 
267  $file_content = file_get_contents($original_file_osencoded);
268  return array('filename'=>$filename, 'content-type' => dol_mimetype($filename), 'filesize'=>filesize($original_file), 'content'=>base64_encode($file_content), 'langcode'=>$outputlangs->defaultlang, 'template'=>$templateused, 'encoding'=>'base64');
269  }
270 
290  public function getDocumentsListByElement($modulepart, $id = 0, $ref = '', $sortfield = '', $sortorder = '')
291  {
292  global $conf;
293 
294  if (empty($modulepart)) {
295  throw new RestException(400, 'bad value for parameter modulepart');
296  }
297 
298  if (empty($id) && empty($ref)) {
299  throw new RestException(400, 'bad value for parameter id or ref');
300  }
301 
302  $id = (empty($id) ? 0 : $id);
303  $recursive = 0;
304  $type = 'files';
305 
306  if ($modulepart == 'societe' || $modulepart == 'thirdparty') {
307  require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
308 
309  if (!DolibarrApiAccess::$user->hasRight('societe', 'lire')) {
310  throw new RestException(401);
311  }
312 
313  $object = new Societe($this->db);
314  $result = $object->fetch($id, $ref);
315  if (!$result) {
316  throw new RestException(404, 'Thirdparty not found');
317  }
318 
319  $upload_dir = $conf->societe->multidir_output[$object->entity]."/".$object->id;
320  } elseif ($modulepart == 'user') {
321  require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
322 
323  // Can get doc if has permission to read all user or if it is user itself
324  if (!DolibarrApiAccess::$user->rights->user->user->lire && DolibarrApiAccess::$user->id != $id) {
325  throw new RestException(401);
326  }
327 
328  $object = new User($this->db);
329  $result = $object->fetch($id, $ref);
330  if (!$result) {
331  throw new RestException(404, 'User not found');
332  }
333 
334  $upload_dir = $conf->user->dir_output.'/'.get_exdir(0, 0, 0, 0, $object, 'user').'/'.$object->id;
335  } elseif ($modulepart == 'adherent' || $modulepart == 'member') {
336  require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
337 
338  if (!DolibarrApiAccess::$user->rights->adherent->lire) {
339  throw new RestException(401);
340  }
341 
342  $object = new Adherent($this->db);
343  $result = $object->fetch($id, $ref);
344  if (!$result) {
345  throw new RestException(404, 'Member not found');
346  }
347 
348  $upload_dir = $conf->adherent->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'member');
349  } elseif ($modulepart == 'propal' || $modulepart == 'proposal') {
350  require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
351 
352  if (!DolibarrApiAccess::$user->hasRight('propal', 'lire')) {
353  throw new RestException(401);
354  }
355 
356  $object = new Propal($this->db);
357  $result = $object->fetch($id, $ref);
358  if (!$result) {
359  throw new RestException(404, 'Proposal not found');
360  }
361 
362  $upload_dir = $conf->propal->multidir_output[$object->entity]."/".get_exdir(0, 0, 0, 1, $object, 'propal');
363  } elseif ($modulepart == 'supplier_proposal') {
364  require_once DOL_DOCUMENT_ROOT.'/supplier_proposal/class/supplier_proposal.class.php';
365 
366  if (!DolibarrApiAccess::$user->rights->supplier_proposal->read) {
367  throw new RestException(401);
368  }
369 
370  $object = new Propal($this->db);
371  $result = $object->fetch($id, $ref);
372  if (!$result) {
373  throw new RestException(404, 'Supplier proposal not found');
374  }
375 
376  $upload_dir = $conf->propal->multidir_output[$object->entity]."/".get_exdir(0, 0, 0, 1, $object, 'propal');
377  } elseif ($modulepart == 'commande' || $modulepart == 'order') {
378  require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
379 
380  if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
381  throw new RestException(401);
382  }
383 
384  $object = new Commande($this->db);
385  $result = $object->fetch($id, $ref);
386  if (!$result) {
387  throw new RestException(404, 'Order not found');
388  }
389 
390  $upload_dir = $conf->commande->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'commande');
391  } elseif ($modulepart == 'commande_fournisseur' || $modulepart == 'supplier_order') {
392  $modulepart = 'supplier_order';
393 
394  require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
395 
396  if (empty(DolibarrApiAccess::$user->rights->fournisseur->commande->lire) && empty(DolibarrApiAccess::$user->rights->supplier_order->lire)) {
397  throw new RestException(401);
398  }
399 
400  $object = new CommandeFournisseur($this->db);
401  $result = $object->fetch($id, $ref);
402  if (!$result) {
403  throw new RestException(404, 'Purchase order not found');
404  }
405 
406  $upload_dir = $conf->fournisseur->dir_output."/commande/".dol_sanitizeFileName($object->ref);
407  } elseif ($modulepart == 'shipment' || $modulepart == 'expedition') {
408  require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
409 
410  if (!DolibarrApiAccess::$user->rights->expedition->lire) {
411  throw new RestException(401);
412  }
413 
414  $object = new Expedition($this->db);
415  $result = $object->fetch($id, $ref);
416  if (!$result) {
417  throw new RestException(404, 'Shipment not found');
418  }
419 
420  $upload_dir = $conf->expedition->dir_output."/sending/".get_exdir(0, 0, 0, 1, $object, 'shipment');
421  } elseif ($modulepart == 'facture' || $modulepart == 'invoice') {
422  require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
423 
424  if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
425  throw new RestException(401);
426  }
427 
428  $object = new Facture($this->db);
429  $result = $object->fetch($id, $ref);
430  if (!$result) {
431  throw new RestException(404, 'Invoice not found');
432  }
433 
434  $upload_dir = $conf->facture->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'invoice');
435  } elseif ($modulepart == 'facture_fournisseur' || $modulepart == 'supplier_invoice') {
436  $modulepart = 'supplier_invoice';
437 
438  require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
439 
440  if (empty(DolibarrApiAccess::$user->rights->fournisseur->facture->lire) && empty(DolibarrApiAccess::$user->rights->supplier_invoice->lire)) {
441  throw new RestException(401);
442  }
443 
444  $object = new FactureFournisseur($this->db);
445  $result = $object->fetch($id, $ref);
446  if (!$result) {
447  throw new RestException(404, 'Invoice not found');
448  }
449 
450  $upload_dir = $conf->fournisseur->dir_output."/facture/".get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier').dol_sanitizeFileName($object->ref);
451  } elseif ($modulepart == 'produit' || $modulepart == 'product') {
452  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
453 
454  if (!DolibarrApiAccess::$user->rights->produit->lire) {
455  throw new RestException(401);
456  }
457 
458  $object = new Product($this->db);
459  $result = $object->fetch($id, $ref);
460  if ($result == 0) {
461  throw new RestException(404, 'Product not found');
462  } elseif ($result < 0) {
463  throw new RestException(500, 'Error while fetching object: '.$object->error);
464  }
465 
466  $upload_dir = $conf->product->multidir_output[$object->entity].'/'.get_exdir(0, 0, 0, 1, $object, 'product');
467  } elseif ($modulepart == 'agenda' || $modulepart == 'action' || $modulepart == 'event') {
468  require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
469 
470  if (!DolibarrApiAccess::$user->rights->agenda->myactions->read && !DolibarrApiAccess::$user->rights->agenda->allactions->read) {
471  throw new RestException(401);
472  }
473 
474  $object = new ActionComm($this->db);
475  $result = $object->fetch($id, $ref);
476  if (!$result) {
477  throw new RestException(404, 'Event not found');
478  }
479 
480  $upload_dir = $conf->agenda->dir_output.'/'.dol_sanitizeFileName($object->ref);
481  } elseif ($modulepart == 'expensereport') {
482  require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
483 
484  if (!DolibarrApiAccess::$user->rights->expensereport->read && !DolibarrApiAccess::$user->rights->expensereport->read) {
485  throw new RestException(401);
486  }
487 
488  $object = new ExpenseReport($this->db);
489  $result = $object->fetch($id, $ref);
490  if (!$result) {
491  throw new RestException(404, 'Expense report not found');
492  }
493 
494  $upload_dir = $conf->expensereport->dir_output.'/'.dol_sanitizeFileName($object->ref);
495  } elseif ($modulepart == 'knowledgemanagement') {
496  require_once DOL_DOCUMENT_ROOT.'/knowledgemanagement/class/knowledgerecord.class.php';
497 
498  if (!DolibarrApiAccess::$user->hasRight('knowledgemanagement', 'knowledgerecord', 'read') && !DolibarrApiAccess::$user->hasRight('knowledgemanagement', 'knowledgerecord', 'read')) {
499  throw new RestException(401);
500  }
501 
502  $object = new KnowledgeRecord($this->db);
503  $result = $object->fetch($id, $ref);
504  if (!$result) {
505  throw new RestException(404, 'KM article not found');
506  }
507 
508  $upload_dir = $conf->knowledgemanagement->dir_output.'/knowledgerecord/'.dol_sanitizeFileName($object->ref);
509  } elseif ($modulepart == 'categorie' || $modulepart == 'category') {
510  require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
511 
512  if (!DolibarrApiAccess::$user->rights->categorie->lire) {
513  throw new RestException(401);
514  }
515 
516  $object = new Categorie($this->db);
517  $result = $object->fetch($id, $ref);
518  if (!$result) {
519  throw new RestException(404, 'Category not found');
520  }
521 
522  $upload_dir = $conf->categorie->multidir_output[$object->entity].'/'.get_exdir($object->id, 2, 0, 0, $object, 'category').$object->id."/photos/".dol_sanitizeFileName($object->ref);
523  } elseif ($modulepart == 'ecm') {
524  throw new RestException(500, 'Modulepart Ecm not implemented yet.');
525  // // require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmdirectory.class.php';
526 
527  // if (!DolibarrApiAccess::$user->rights->ecm->read) {
528  // throw new RestException(401);
529  // }
530 
531  // // $object = new EcmDirectory($this->db);
532  // // $result = $object->fetch($ref);
533  // // if (!$result) {
534  // // throw new RestException(404, 'EcmDirectory not found');
535  // // }
536  // $upload_dir = $conf->ecm->dir_output;
537  // $type = 'all';
538  // $recursive = 0;
539  } elseif ($modulepart == 'contrat' || $modulepart == 'contract') {
540  $modulepart = 'contrat';
541  require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
542 
543  $object = new Contrat($this->db);
544  $result = $object->fetch($id, $ref);
545  if (!$result) {
546  throw new RestException(404, 'Contract not found');
547  }
548 
549  $upload_dir = $conf->contrat->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'contract');
550  } elseif ($modulepart == 'projet' || $modulepart == 'project') {
551  $modulepart = 'project';
552  require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
553 
554  $object = new Project($this->db);
555  $result = $object->fetch($id, $ref);
556  if (!$result) {
557  throw new RestException(404, 'Project not found');
558  }
559 
560  $upload_dir = $conf->projet->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'project');
561  } else {
562  throw new RestException(500, 'Modulepart '.$modulepart.' not implemented yet.');
563  }
564 
565  $objectType = $modulepart;
566  if (! empty($object->id) && ! empty($object->table_element)) {
567  $objectType = $object->table_element;
568  }
569 
570  $filearray = dol_dir_list($upload_dir, $type, $recursive, '', '(\.meta|_preview.*\.png)$', $sortfield, (strtolower($sortorder) == 'desc' ?SORT_DESC:SORT_ASC), 1);
571  if (empty($filearray)) {
572  throw new RestException(404, 'Search for modulepart '.$modulepart.' with Id '.$object->id.(!empty($object->ref) ? ' or Ref '.$object->ref : '').' does not return any document.');
573  } else {
574  if (($object->id) > 0 && !empty($modulepart)) {
575  require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
576  $ecmfile = new EcmFiles($this->db);
577  $result = $ecmfile->fetchAll('', '', 0, 0, array('t.src_object_type' => $objectType, 't.src_object_id' => $object->id));
578  if ($result < 0) {
579  throw new RestException(503, 'Error when retrieve ecm list : '.$this->db->lasterror());
580  } elseif (is_array($ecmfile->lines) && count($ecmfile->lines) > 0) {
581  $count = count($filearray);
582  for ($i = 0 ; $i < $count ; $i++) {
583  if ($filearray[$i]['name'] == $ecmfile->lines[$i]->filename) $filearray[$i] = array_merge($filearray[$i], (array) $ecmfile->lines[0]);
584  }
585  }
586  }
587  }
588 
589  return $filearray;
590  }
591 
592 
601  /*
602  public function get($id) {
603  return array('note'=>'xxx');
604  }*/
605 
606 
633  public function post($filename, $modulepart, $ref = '', $subdir = '', $filecontent = '', $fileencoding = '', $overwriteifexists = 0, $createdirifnotexists = 1)
634  {
635  global $db, $conf;
636 
637  //var_dump($modulepart);
638  //var_dump($filename);
639  //var_dump($filecontent);exit;
640 
641  if (empty($modulepart)) {
642  throw new RestException(400, 'Modulepart not provided.');
643  }
644 
645  if (!DolibarrApiAccess::$user->rights->ecm->upload) {
646  throw new RestException(401);
647  }
648 
649  $newfilecontent = '';
650  if (empty($fileencoding)) {
651  $newfilecontent = $filecontent;
652  }
653  if ($fileencoding == 'base64') {
654  $newfilecontent = base64_decode($filecontent);
655  }
656 
657  $original_file = dol_sanitizeFileName($filename);
658 
659  // Define $uploadir
660  $object = null;
661  $entity = DolibarrApiAccess::$user->entity;
662  if (empty($entity)) {
663  $entity = 1;
664  }
665 
666  if ($ref) {
667  $tmpreldir = '';
668  $fetchbyid = false;
669 
670  if ($modulepart == 'facture' || $modulepart == 'invoice') {
671  $modulepart = 'facture';
672 
673  require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
674  $object = new Facture($this->db);
675  } elseif ($modulepart == 'facture_fournisseur' || $modulepart == 'supplier_invoice') {
676  $modulepart = 'supplier_invoice';
677 
678  require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
679  $object = new FactureFournisseur($this->db);
680  } elseif ($modulepart == 'commande' || $modulepart == 'order') {
681  $modulepart = 'commande';
682 
683  require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
684  $object = new Commande($this->db);
685  } elseif ($modulepart == 'commande_fournisseur' || $modulepart == 'supplier_order') {
686  $modulepart = 'supplier_order';
687 
688  require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
689  $object = new CommandeFournisseur($this->db);
690  } elseif ($modulepart == 'projet' || $modulepart == 'project') {
691  require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
692  $object = new Project($this->db);
693  } elseif ($modulepart == 'task' || $modulepart == 'project_task') {
694  $modulepart = 'project_task';
695 
696  require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
697  $object = new Task($this->db);
698 
699  $task_result = $object->fetch('', $ref);
700 
701  // Fetching the tasks project is required because its out_dir might be a sub-directory of the project
702  if ($task_result > 0) {
703  $project_result = $object->fetch_projet();
704 
705  if ($project_result >= 0) {
706  $tmpreldir = dol_sanitizeFileName($object->project->ref).'/';
707  }
708  } else {
709  throw new RestException(500, 'Error while fetching Task '.$ref);
710  }
711  } elseif ($modulepart == 'product' || $modulepart == 'produit' || $modulepart == 'service' || $modulepart == 'produit|service') {
712  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
713  $object = new Product($this->db);
714  } elseif ($modulepart == 'expensereport') {
715  require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
716  $object = new ExpenseReport($this->db);
717  } elseif ($modulepart == 'fichinter') {
718  require_once DOL_DOCUMENT_ROOT.'/fichinter/class/fichinter.class.php';
719  $object = new Fichinter($this->db);
720  } elseif ($modulepart == 'adherent' || $modulepart == 'member') {
721  $modulepart = 'adherent';
722  require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
723  $object = new Adherent($this->db);
724  } elseif ($modulepart == 'proposal' || $modulepart == 'propal' || $modulepart == 'propale') {
725  $modulepart = 'propale';
726  require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
727  $object = new Propal($this->db);
728  } elseif ($modulepart == 'agenda' || $modulepart == 'action' || $modulepart == 'event') {
729  $modulepart = 'agenda';
730  require_once DOL_DOCUMENT_ROOT . '/comm/action/class/actioncomm.class.php';
731  $object = new ActionComm($this->db);
732  } elseif ($modulepart == 'contact' || $modulepart == 'socpeople') {
733  $modulepart = 'contact';
734  require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
735  $object = new Contact($this->db);
736  $fetchbyid = true;
737  } elseif ($modulepart == 'contrat' || $modulepart == 'contract') {
738  $modulepart = 'contrat';
739  require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
740  $object = new Contrat($this->db);
741  } else {
742  // TODO Implement additional moduleparts
743  throw new RestException(500, 'Modulepart '.$modulepart.' not implemented yet.');
744  }
745 
746  if (is_object($object)) {
747  if ($fetchbyid) {
748  $result = $object->fetch($ref);
749  } else {
750  $result = $object->fetch('', $ref);
751  }
752 
753  if ($result == 0) {
754  throw new RestException(404, "Object with ref '".$ref."' was not found.");
755  } elseif ($result < 0) {
756  throw new RestException(500, 'Error while fetching object: '.$object->error);
757  }
758  }
759 
760  if (!($object->id > 0)) {
761  throw new RestException(404, 'The object '.$modulepart." with ref '".$ref."' was not found.");
762  }
763 
764  // Special cases that need to use get_exdir to get real dir of object
765  // In future, all object should use this to define path of documents.
766  if ($modulepart == 'supplier_invoice') {
767  $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
768  }
769 
770  $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref);
771 
772  $tmp = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, $ref, 'write');
773  $upload_dir = $tmp['original_file']; // No dirname here, tmp['original_file'] is already the dir because dol_check_secure_access_document was called with param original_file that is only the dir
774 
775  if (empty($upload_dir) || $upload_dir == '/') {
776  throw new RestException(500, 'This value of modulepart ('.$modulepart.') does not support yet usage of ref. Check modulepart parameter or try to use subdir parameter instead of ref.');
777  }
778  } else {
779  if ($modulepart == 'invoice') {
780  $modulepart = 'facture';
781  }
782  if ($modulepart == 'member') {
783  $modulepart = 'adherent';
784  }
785 
786  $relativefile = $subdir;
787  $tmp = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'write');
788  $upload_dir = $tmp['original_file']; // No dirname here, tmp['original_file'] is already the dir because dol_check_secure_access_document was called with param original_file that is only the dir
789 
790  if (empty($upload_dir) || $upload_dir == '/') {
791  if (!empty($tmp['error'])) {
792  throw new RestException(401, 'Error returned by dol_check_secure_access_document: '.$tmp['error']);
793  } else {
794  throw new RestException(500, 'This value of modulepart ('.$modulepart.') is not allowed with this value of subdir ('.$relativefile.')');
795  }
796  }
797  }
798  // $original_file here is still value of filename without any dir.
799 
800  $upload_dir = dol_sanitizePathName($upload_dir);
801 
802  if (!empty($createdirifnotexists)) {
803  if (dol_mkdir($upload_dir) < 0) { // needed by products
804  throw new RestException(500, 'Error while trying to create directory '.$upload_dir);
805  }
806  }
807 
808  $destfile = $upload_dir.'/'.$original_file;
809  $destfiletmp = DOL_DATA_ROOT.'/admin/temp/'.$original_file;
810  dol_delete_file($destfiletmp);
811  //var_dump($original_file);exit;
812 
813  if (!dol_is_dir(dirname($destfile))) {
814  throw new RestException(401, 'Directory not exists : '.dirname($destfile));
815  }
816 
817  if (!$overwriteifexists && dol_is_file($destfile)) {
818  throw new RestException(500, "File with name '".$original_file."' already exists.");
819  }
820 
821  // in case temporary directory admin/temp doesn't exist
822  if (!dol_is_dir(dirname($destfiletmp))) {
823  dol_mkdir(dirname($destfiletmp));
824  }
825 
826  $fhandle = @fopen($destfiletmp, 'w');
827  if ($fhandle) {
828  $nbofbyteswrote = fwrite($fhandle, $newfilecontent);
829  fclose($fhandle);
830  dolChmod($destfiletmp);
831  } else {
832  throw new RestException(500, "Failed to open file '".$destfiletmp."' for write");
833  }
834 
835  $disablevirusscan = 0;
836  $src_file = $destfiletmp;
837  $dest_file = $destfile;
838 
839  // Security:
840  // If we need to make a virus scan
841  if (empty($disablevirusscan) && file_exists($src_file)) {
842  $checkvirusarray = dolCheckVirus($src_file);
843  if (count($checkvirusarray)) {
844  dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: errors='.join(',', $checkvirusarray), LOG_WARNING);
845  throw new RestException(500, 'ErrorFileIsInfectedWithAVirus: '.join(',', $checkvirusarray));
846  }
847  }
848 
849  // Security:
850  // Disallow file with some extensions. We rename them.
851  // Because if we put the documents directory into a directory inside web root (very bad), this allows to execute on demand arbitrary code.
852  if (isAFileWithExecutableContent($dest_file) && empty($conf->global->MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED)) {
853  // $upload_dir ends with a slash, so be must be sure the medias dir to compare to ends with slash too.
854  $publicmediasdirwithslash = $conf->medias->multidir_output[$conf->entity];
855  if (!preg_match('/\/$/', $publicmediasdirwithslash)) {
856  $publicmediasdirwithslash .= '/';
857  }
858 
859  if (strpos($upload_dir, $publicmediasdirwithslash) !== 0 || !getDolGlobalInt("MAIN_DOCUMENT_DISABLE_NOEXE_IN_MEDIAS_DIR")) { // We never add .noexe on files into media directory
860  $dest_file .= '.noexe';
861  }
862  }
863 
864  // Security:
865  // We refuse cache files/dirs, upload using .. and pipes into filenames.
866  if (preg_match('/^\./', basename($src_file)) || preg_match('/\.\./', $src_file) || preg_match('/[<>|]/', $src_file)) {
867  dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING);
868  throw new RestException(500, "Refused to deliver file ".$src_file);
869  }
870 
871  // Security:
872  // We refuse cache files/dirs, upload using .. and pipes into filenames.
873  if (preg_match('/^\./', basename($dest_file)) || preg_match('/\.\./', $dest_file) || preg_match('/[<>|]/', $dest_file)) {
874  dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING);
875  throw new RestException(500, "Refused to deliver file ".$dest_file);
876  }
877 
878  $result = dol_move($destfiletmp, $dest_file, 0, $overwriteifexists, 1, 1);
879  if (!$result) {
880  throw new RestException(500, "Failed to move file into '".$destfile."'");
881  }
882 
883  return dol_basename($destfile);
884  }
885 
899  public function delete($modulepart, $original_file)
900  {
901  global $conf, $langs;
902 
903  if (empty($modulepart)) {
904  throw new RestException(400, 'bad value for parameter modulepart');
905  }
906  if (empty($original_file)) {
907  throw new RestException(400, 'bad value for parameter original_file');
908  }
909 
910  //--- Finds and returns the document
911  $entity = $conf->entity;
912 
913  // Special cases that need to use get_exdir to get real dir of object
914  // If future, all object should use this to define path of documents.
915  /*
916  $tmpreldir = '';
917  if ($modulepart == 'supplier_invoice') {
918  $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
919  }
920 
921  $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref); */
922  $relativefile = $original_file;
923 
924  $check_access = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'read');
925  $accessallowed = $check_access['accessallowed'];
926  $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals'];
927  $original_file = $check_access['original_file'];
928 
929  if (preg_match('/\.\./', $original_file) || preg_match('/[<>|]/', $original_file)) {
930  throw new RestException(401);
931  }
932  if (!$accessallowed) {
933  throw new RestException(401);
934  }
935 
936  $filename = basename($original_file);
937  $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset
938 
939  if (!file_exists($original_file_osencoded)) {
940  dol_syslog("Try to download not found file ".$original_file_osencoded, LOG_WARNING);
941  throw new RestException(404, 'File not found');
942  }
943 
944  if (@unlink($original_file_osencoded)) {
945  return array(
946  'success' => array(
947  'code' => 200,
948  'message' => 'Document deleted'
949  )
950  );
951  }
952 
953  throw new RestException(401);
954  }
955 
956  // phpcs:disable PEAR.NamingConventions.ValidFunctionName
964  private function _validate_file($data)
965  {
966  // phpcs:enable
967  $result = array();
968  foreach (Documents::$DOCUMENT_FIELDS as $field) {
969  if (!isset($data[$field])) {
970  throw new RestException(400, "$field field missing");
971  }
972  $result[$field] = $data[$field];
973  }
974  return $result;
975  }
976 }
Class to manage agenda events (actions)
Class to manage members of a foundation.
Class to manage categories.
Class to manage predefined suppliers products.
Class to manage customers orders.
Class to manage contact/addresses.
Class to manage contracts.
API class for receive files.
post($filename, $modulepart, $ref='', $subdir='', $filecontent='', $fileencoding='', $overwriteifexists=0, $createdirifnotexists=1)
Return a document.
__construct()
Constructor.
index($modulepart, $original_file='')
Download a document.
getDocumentsListByElement($modulepart, $id=0, $ref='', $sortfield='', $sortorder='')
Return the list of documents of a dedicated element (from its ID or Ref)
builddoc($modulepart, $original_file='', $doctemplate='', $langcode='')
Build a document.
_validate_file($data)
Validate fields before create or update object.
Class for API REST v1.
Definition: api.class.php:31
Class to manage ECM files.
Class to manage shipments.
Class to manage Trips and Expenses.
Class to manage suppliers invoices.
Class to manage invoices.
Class to manage interventions.
Class for KnowledgeRecord.
Class to manage products or services.
Class to manage projects.
Class to manage proposals.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage tasks.
Definition: task.class.php:40
Class to manage translations.
Class to manage Dolibarr users.
Definition: user.class.php:48
dolCheckVirus($src_file)
Check virus into a file.
Definition: files.lib.php:1157
dol_basename($pathfile)
Make a basename working with all page code (default PHP basenamed fails with cyrillic).
Definition: files.lib.php:37
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
Definition: files.lib.php:1334
dol_check_secure_access_document($modulepart, $original_file, $entity, $fuser='', $refname='', $mode='read')
Security check when accessing to a document (used by document.php, viewimage.php and webservices to g...
Definition: files.lib.php:2543
dol_is_file($pathoffile)
Return if path is a file.
Definition: files.lib.php:483
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:62
dol_is_dir($folder)
Test if filename is a directory.
Definition: files.lib.php:453
dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvirus=0, $indexdatabase=1)
Move a file into another name.
Definition: files.lib.php:947
dol_mimetype($file, $default='application/octet-stream', $mode=0)
Return MIME type of a file from its name with extension.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
dolChmod($filepath, $newmask='')
Change mod of a file.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
isAFileWithExecutableContent($filename)
Return if a file can contains executable content.
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_sanitizePathName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a path name.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)