dolibarr  18.0.6
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) {
584  $filearray[$i] = array_merge($filearray[$i], (array) $ecmfile->lines[0]);
585  }
586  }
587  }
588  }
589  }
590 
591  return $filearray;
592  }
593 
594 
603  /*
604  public function get($id) {
605  return array('note'=>'xxx');
606  }*/
607 
608 
635  public function post($filename, $modulepart, $ref = '', $subdir = '', $filecontent = '', $fileencoding = '', $overwriteifexists = 0, $createdirifnotexists = 1)
636  {
637  global $db, $conf;
638 
639  //var_dump($modulepart);
640  //var_dump($filename);
641  //var_dump($filecontent);exit;
642 
643  $modulepartorig = $modulepart;
644 
645  if (empty($modulepart)) {
646  throw new RestException(400, 'Modulepart not provided.');
647  }
648 
649  if (!DolibarrApiAccess::$user->rights->ecm->upload) {
650  throw new RestException(401);
651  }
652 
653  $newfilecontent = '';
654  if (empty($fileencoding)) {
655  $newfilecontent = $filecontent;
656  }
657  if ($fileencoding == 'base64') {
658  $newfilecontent = base64_decode($filecontent);
659  }
660 
661  $original_file = dol_sanitizeFileName($filename);
662 
663  // Define $uploadir
664  $object = null;
665  $entity = DolibarrApiAccess::$user->entity;
666  if (empty($entity)) {
667  $entity = 1;
668  }
669 
670  if ($ref) {
671  $tmpreldir = '';
672  $fetchbyid = false;
673 
674  if ($modulepart == 'facture' || $modulepart == 'invoice') {
675  $modulepart = 'facture';
676 
677  require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
678  $object = new Facture($this->db);
679  } elseif ($modulepart == 'facture_fournisseur' || $modulepart == 'supplier_invoice') {
680  $modulepart = 'supplier_invoice';
681 
682  require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
683  $object = new FactureFournisseur($this->db);
684  } elseif ($modulepart == 'commande' || $modulepart == 'order') {
685  $modulepart = 'commande';
686 
687  require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
688  $object = new Commande($this->db);
689  } elseif ($modulepart == 'commande_fournisseur' || $modulepart == 'supplier_order') {
690  $modulepart = 'supplier_order';
691 
692  require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
693  $object = new CommandeFournisseur($this->db);
694  } elseif ($modulepart == 'projet' || $modulepart == 'project') {
695  require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
696  $object = new Project($this->db);
697  } elseif ($modulepart == 'task' || $modulepart == 'project_task') {
698  $modulepart = 'project_task';
699 
700  require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
701  $object = new Task($this->db);
702 
703  $task_result = $object->fetch('', $ref);
704 
705  // Fetching the tasks project is required because its out_dir might be a sub-directory of the project
706  if ($task_result > 0) {
707  $project_result = $object->fetch_projet();
708 
709  if ($project_result >= 0) {
710  $tmpreldir = dol_sanitizeFileName($object->project->ref).'/';
711  }
712  } else {
713  throw new RestException(500, 'Error while fetching Task '.$ref);
714  }
715  } elseif ($modulepart == 'product' || $modulepart == 'produit' || $modulepart == 'service' || $modulepart == 'produit|service') {
716  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
717  $object = new Product($this->db);
718  } elseif ($modulepart == 'expensereport') {
719  require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
720  $object = new ExpenseReport($this->db);
721  } elseif ($modulepart == 'fichinter') {
722  require_once DOL_DOCUMENT_ROOT.'/fichinter/class/fichinter.class.php';
723  $object = new Fichinter($this->db);
724  } elseif ($modulepart == 'adherent' || $modulepart == 'member') {
725  $modulepart = 'adherent';
726  require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
727  $object = new Adherent($this->db);
728  } elseif ($modulepart == 'proposal' || $modulepart == 'propal' || $modulepart == 'propale') {
729  $modulepart = 'propale';
730  require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
731  $object = new Propal($this->db);
732  } elseif ($modulepart == 'agenda' || $modulepart == 'action' || $modulepart == 'event') {
733  $modulepart = 'agenda';
734  require_once DOL_DOCUMENT_ROOT . '/comm/action/class/actioncomm.class.php';
735  $object = new ActionComm($this->db);
736  } elseif ($modulepart == 'contact' || $modulepart == 'socpeople') {
737  $modulepart = 'contact';
738  require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
739  $object = new Contact($this->db);
740  $fetchbyid = true;
741  } elseif ($modulepart == 'contrat' || $modulepart == 'contract') {
742  $modulepart = 'contrat';
743  require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
744  $object = new Contrat($this->db);
745  } else {
746  // TODO Implement additional moduleparts
747  throw new RestException(500, 'Modulepart '.$modulepart.' not implemented yet.');
748  }
749 
750  if (is_object($object)) {
751  if ($fetchbyid) {
752  $result = $object->fetch($ref);
753  } else {
754  $result = $object->fetch('', $ref);
755  }
756 
757  if ($result == 0) {
758  throw new RestException(404, "Object with ref '".$ref."' was not found.");
759  } elseif ($result < 0) {
760  throw new RestException(500, 'Error while fetching object: '.$object->error);
761  }
762  }
763 
764  if (!($object->id > 0)) {
765  throw new RestException(404, 'The object '.$modulepart." with ref '".$ref."' was not found.");
766  }
767 
768  // Special cases that need to use get_exdir to get real dir of object
769  // In future, all object should use this to define path of documents.
770  if ($modulepart == 'supplier_invoice') {
771  $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
772  }
773 
774  $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref);
775 
776  $tmp = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, $ref, 'write');
777  $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
778 
779  if (empty($upload_dir) || $upload_dir == '/') {
780  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.');
781  }
782  } else {
783  if ($modulepart == 'invoice') {
784  $modulepart = 'facture';
785  }
786  if ($modulepart == 'member') {
787  $modulepart = 'adherent';
788  }
789 
790  $relativefile = $subdir;
791  $tmp = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'write');
792  $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
793 
794  if (empty($upload_dir) || $upload_dir == '/') {
795  if (!empty($tmp['error'])) {
796  throw new RestException(401, 'Error returned by dol_check_secure_access_document: '.$tmp['error']);
797  } else {
798  throw new RestException(500, 'This value of modulepart ('.$modulepart.') is not allowed with this value of subdir ('.$relativefile.')');
799  }
800  }
801  }
802  // $original_file here is still value of filename without any dir.
803 
804  $upload_dir = dol_sanitizePathName($upload_dir);
805 
806  if (!empty($createdirifnotexists)) {
807  if (dol_mkdir($upload_dir) < 0) { // needed by products
808  throw new RestException(500, 'Error while trying to create directory '.$upload_dir);
809  }
810  }
811 
812  $destfile = $upload_dir.'/'.$original_file;
813  $destfiletmp = DOL_DATA_ROOT.'/admin/temp/'.$original_file;
814  dol_delete_file($destfiletmp);
815  //var_dump($original_file);exit;
816 
817  if (!dol_is_dir(dirname($destfile))) {
818  throw new RestException(401, 'Directory not exists : '.dirname($destfile));
819  }
820 
821  if (!$overwriteifexists && dol_is_file($destfile)) {
822  throw new RestException(500, "File with name '".$original_file."' already exists.");
823  }
824 
825  // in case temporary directory admin/temp doesn't exist
826  if (!dol_is_dir(dirname($destfiletmp))) {
827  dol_mkdir(dirname($destfiletmp));
828  }
829 
830  $fhandle = @fopen($destfiletmp, 'w');
831  if ($fhandle) {
832  $nbofbyteswrote = fwrite($fhandle, $newfilecontent);
833  fclose($fhandle);
834  dolChmod($destfiletmp);
835  } else {
836  throw new RestException(500, "Failed to open file '".$destfiletmp."' for write");
837  }
838 
839  $disablevirusscan = 0;
840  $src_file = $destfiletmp;
841  $dest_file = $destfile;
842 
843  // Security:
844  // If we need to make a virus scan
845  if (empty($disablevirusscan) && file_exists($src_file)) {
846  $checkvirusarray = dolCheckVirus($src_file);
847  if (count($checkvirusarray)) {
848  dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: errors='.join(',', $checkvirusarray), LOG_WARNING);
849  throw new RestException(500, 'ErrorFileIsInfectedWithAVirus: '.join(',', $checkvirusarray));
850  }
851  }
852 
853  // Security:
854  // Disallow file with some extensions. We rename them.
855  // Because if we put the documents directory into a directory inside web root (very bad), this allows to execute on demand arbitrary code.
856  if (isAFileWithExecutableContent($dest_file) && empty($conf->global->MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED)) {
857  // $upload_dir ends with a slash, so be must be sure the medias dir to compare to ends with slash too.
858  $publicmediasdirwithslash = $conf->medias->multidir_output[$conf->entity];
859  if (!preg_match('/\/$/', $publicmediasdirwithslash)) {
860  $publicmediasdirwithslash .= '/';
861  }
862 
863  if (strpos($upload_dir, $publicmediasdirwithslash) !== 0 || !getDolGlobalInt("MAIN_DOCUMENT_DISABLE_NOEXE_IN_MEDIAS_DIR")) { // We never add .noexe on files into media directory
864  $dest_file .= '.noexe';
865  }
866  }
867 
868  // Security:
869  // We refuse cache files/dirs, upload using .. and pipes into filenames.
870  if (preg_match('/^\./', basename($src_file)) || preg_match('/\.\./', $src_file) || preg_match('/[<>|]/', $src_file)) {
871  dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING);
872  throw new RestException(500, "Refused to deliver file ".$src_file);
873  }
874 
875  // Security:
876  // We refuse cache files/dirs, upload using .. and pipes into filenames.
877  if (preg_match('/^\./', basename($dest_file)) || preg_match('/\.\./', $dest_file) || preg_match('/[<>|]/', $dest_file)) {
878  dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING);
879  throw new RestException(500, "Refused to deliver file ".$dest_file);
880  }
881 
882  $moreinfo = array('note_private' => 'File uploaded using API /documents from IP '.getUserRemoteIP());
883  if (!empty($object) && is_object($object) && $object->id > 0) {
884  $moreinfo['src_object_type'] = $object->table_element;
885  $moreinfo['src_object_id'] = $object->id;
886  }
887 
888  // Move the temporary file at its final emplacement
889  $result = dol_move($destfiletmp, $dest_file, 0, $overwriteifexists, 1, 1, $moreinfo);
890  if (!$result) {
891  throw new RestException(500, "Failed to move file into '".$destfile."'");
892  }
893 
894  return dol_basename($destfile);
895  }
896 
910  public function delete($modulepart, $original_file)
911  {
912  global $conf, $langs;
913 
914  if (empty($modulepart)) {
915  throw new RestException(400, 'bad value for parameter modulepart');
916  }
917  if (empty($original_file)) {
918  throw new RestException(400, 'bad value for parameter original_file');
919  }
920 
921  //--- Finds and returns the document
922  $entity = $conf->entity;
923 
924  // Special cases that need to use get_exdir to get real dir of object
925  // If future, all object should use this to define path of documents.
926  /*
927  $tmpreldir = '';
928  if ($modulepart == 'supplier_invoice') {
929  $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
930  }
931 
932  $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref); */
933  $relativefile = $original_file;
934 
935  $check_access = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'read');
936  $accessallowed = $check_access['accessallowed'];
937  $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals'];
938  $original_file = $check_access['original_file'];
939 
940  if (preg_match('/\.\./', $original_file) || preg_match('/[<>|]/', $original_file)) {
941  throw new RestException(401);
942  }
943  if (!$accessallowed) {
944  throw new RestException(401);
945  }
946 
947  $filename = basename($original_file);
948  $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset
949 
950  if (!file_exists($original_file_osencoded)) {
951  dol_syslog("Try to download not found file ".$original_file_osencoded, LOG_WARNING);
952  throw new RestException(404, 'File not found');
953  }
954 
955  if (@unlink($original_file_osencoded)) {
956  return array(
957  'success' => array(
958  'code' => 200,
959  'message' => 'Document deleted'
960  )
961  );
962  }
963 
964  throw new RestException(401);
965  }
966 
967  // phpcs:disable PEAR.NamingConventions.ValidFunctionName
975  private function _validate_file($data)
976  {
977  // phpcs:enable
978  $result = array();
979  foreach (Documents::$DOCUMENT_FIELDS as $field) {
980  if (!isset($data[$field])) {
981  throw new RestException(400, "$field field missing");
982  }
983  $result[$field] = $data[$field];
984  }
985  return $result;
986  }
987 }
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:1179
dol_basename($pathfile)
Make a basename working with all page code (default PHP basenamed fails with cyrillic).
Definition: files.lib.php:37
dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvirus=0, $indexdatabase=1, $moreinfo=array())
Move a file into another name.
Definition: files.lib.php:948
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:1356
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:2565
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_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.
getUserRemoteIP()
Return the IP of remote user.
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)