dolibarr 18.0.9
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 * Copyright (C) 2025 William Mead <william@m34d.com>
7 *
8 * This program is free software you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22use Luracast\Restler\RestException;
23use Luracast\Restler\Format\UploadFormat;
24
25require_once DOL_DOCUMENT_ROOT.'/main.inc.php';
26require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
27
35{
36
40 public static $DOCUMENT_FIELDS = array(
41 'modulepart'
42 );
43
47 public function __construct()
48 {
49 global $db;
50 $this->db = $db;
51 }
52
53
70 public function index($modulepart, $original_file = '')
71 {
72 global $conf, $langs;
73
74 if (empty($modulepart)) {
75 throw new RestException(400, 'bad value for parameter modulepart');
76 }
77 if (empty($original_file)) {
78 throw new RestException(400, 'bad value for parameter original_file');
79 }
80
81 //--- Finds and returns the document
82 $entity = $conf->entity;
83
84 // Special cases that need to use get_exdir to get real dir of object
85 // If future, all object should use this to define path of documents.
86 /*
87 $tmpreldir = '';
88 if ($modulepart == 'supplier_invoice') {
89 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
90 }
91
92 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref); */
93 $relativefile = $original_file;
94
95 $check_access = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'read');
96 $accessallowed = $check_access['accessallowed'];
97 $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals'];
98 $original_file = $check_access['original_file'];
99
100 if (preg_match('/\.\./', $original_file) || preg_match('/[<>|]/', $original_file)) {
101 throw new RestException(401);
102 }
103 if (!$accessallowed) {
104 throw new RestException(401);
105 }
106
107 if (DolibarrApiAccess::$user->socid > 0) {
108 if ($sqlprotectagainstexternals) {
109 $resql = $this->db->query($sqlprotectagainstexternals);
110 if ($resql) {
111 $num = $this->db->num_rows($resql);
112 $i = 0;
113 while ($i < $num) {
114 $obj = $this->db->fetch_object($resql);
115 if (DolibarrApiAccess::$user->socid != $obj->fk_soc) {
116 throw new RestException(403, 'Not allowed to download documents with such a ref');
117 }
118 $i++;
119 }
120 }
121 }
122 }
123
124 $filename = basename($original_file);
125 $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset
126
127 if (!file_exists($original_file_osencoded)) {
128 dol_syslog("Try to download not found file ".$original_file_osencoded, LOG_WARNING);
129 throw new RestException(404, 'File not found');
130 }
131
132 $file_content = file_get_contents($original_file_osencoded);
133 return array('filename'=>$filename, 'content-type' => dol_mimetype($filename), 'filesize'=>filesize($original_file), 'content'=>base64_encode($file_content), 'encoding'=>'base64');
134 }
135
136
158 public function builddoc($modulepart, $original_file = '', $doctemplate = '', $langcode = '')
159 {
160 global $conf, $langs;
161
162 if (empty($modulepart)) {
163 throw new RestException(400, 'bad value for parameter modulepart');
164 }
165 if (empty($original_file)) {
166 throw new RestException(400, 'bad value for parameter original_file');
167 }
168
169 $outputlangs = $langs;
170 if ($langcode && $langs->defaultlang != $langcode) {
171 $outputlangs = new Translate('', $conf);
172 $outputlangs->setDefaultLang($langcode);
173 }
174
175 //--- Finds and returns the document
176 $entity = $conf->entity;
177
178 // Special cases that need to use get_exdir to get real dir of object
179 // If future, all object should use this to define path of documents.
180 /*
181 $tmpreldir = '';
182 if ($modulepart == 'supplier_invoice') {
183 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
184 }
185
186 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref); */
187 $relativefile = $original_file;
188
189 $check_access = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'write');
190 $accessallowed = $check_access['accessallowed'];
191 $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals'];
192 $original_file = $check_access['original_file'];
193
194 if (preg_match('/\.\./', $original_file) || preg_match('/[<>|]/', $original_file)) {
195 throw new RestException(401);
196 }
197 if (!$accessallowed) {
198 throw new RestException(401);
199 }
200
201 if (DolibarrApiAccess::$user->socid > 0) {
202 if ($sqlprotectagainstexternals) {
203 $resql = $this->db->query($sqlprotectagainstexternals);
204 if ($resql) {
205 $num = $this->db->num_rows($resql);
206 $i = 0;
207 while ($i < $num) {
208 $obj = $this->db->fetch_object($resql);
209 if (DolibarrApiAccess::$user->socid != $obj->fk_soc) {
210 throw new RestException(403, 'Not allowed to download documents with such a ref');
211 }
212 $i++;
213 }
214 }
215 }
216 }
217
218 // --- Generates the document
219 $hidedetails = empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS) ? 0 : 1;
220 $hidedesc = empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DESC) ? 0 : 1;
221 $hideref = empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_REF) ? 0 : 1;
222
223 $templateused = '';
224
225 if ($modulepart == 'facture' || $modulepart == 'invoice') {
226 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
227 $this->invoice = new Facture($this->db);
228 $result = $this->invoice->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
229 if (!$result) {
230 throw new RestException(404, 'Invoice not found');
231 }
232
233 $templateused = $doctemplate ? $doctemplate : $this->invoice->model_pdf;
234 $result = $this->invoice->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
235 if ($result <= 0) {
236 throw new RestException(500, 'Error generating document');
237 }
238 } elseif ($modulepart == 'facture_fournisseur' || $modulepart == 'invoice_supplier') {
239 require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.facture.class.php';
240 $this->supplier_invoice = new FactureFournisseur($this->db);
241 $result = $this->supplier_invoice->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
242 if (!$result) {
243 throw new RestException(404, 'Supplier invoice not found');
244 }
245
246 $templateused = $doctemplate ? $doctemplate : $this->supplier_invoice->model_pdf;
247 $result = $this->supplier_invoice->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
248 if ($result < 0) {
249 throw new RestException(500, 'Error generating document');
250 }
251 } elseif ($modulepart == 'commande' || $modulepart == 'order') {
252 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
253 $this->order = new Commande($this->db);
254 $result = $this->order->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
255 if (!$result) {
256 throw new RestException(404, 'Order not found');
257 }
258 $templateused = $doctemplate ? $doctemplate : $this->order->model_pdf;
259 $result = $this->order->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
260 if ($result <= 0) {
261 throw new RestException(500, 'Error generating document');
262 }
263 } elseif ($modulepart == 'propal' || $modulepart == 'proposal') {
264 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
265 $this->propal = new Propal($this->db);
266 $result = $this->propal->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
267 if (!$result) {
268 throw new RestException(404, 'Proposal not found');
269 }
270 $templateused = $doctemplate ? $doctemplate : $this->propal->model_pdf;
271 $result = $this->propal->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
272 if ($result <= 0) {
273 throw new RestException(500, 'Error generating document');
274 }
275 } elseif ($modulepart == 'contrat' || $modulepart == 'contract') {
276 require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
277
278 $this->contract = new Contrat($this->db);
279 $result = $this->contract->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
280
281 if (!$result) {
282 throw new RestException(404, 'Contract not found');
283 }
284
285 $templateused = $doctemplate ? $doctemplate : $this->contract->model_pdf;
286 $result = $this->contract->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
287
288 if ($result <= 0) {
289 throw new RestException(500, 'Error generating document missing doctemplate parameter');
290 }
291 } else {
292 throw new RestException(403, 'Generation not available for this modulepart');
293 }
294
295 $filename = basename($original_file);
296 $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset
297
298 if (!file_exists($original_file_osencoded)) {
299 throw new RestException(404, 'File not found');
300 }
301
302 $file_content = file_get_contents($original_file_osencoded);
303 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');
304 }
305
325 public function getDocumentsListByElement($modulepart, $id = 0, $ref = '', $sortfield = '', $sortorder = '')
326 {
327 global $conf;
328
329 if (empty($modulepart)) {
330 throw new RestException(400, 'bad value for parameter modulepart');
331 }
332
333 if (empty($id) && empty($ref)) {
334 throw new RestException(400, 'bad value for parameter id or ref');
335 }
336
337 $id = (empty($id) ? 0 : $id);
338 $recursive = 0;
339 $type = 'files';
340
341 if ($modulepart == 'societe' || $modulepart == 'thirdparty') {
342 require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
343
344 if (!DolibarrApiAccess::$user->hasRight('societe', 'lire')) {
345 throw new RestException(401);
346 }
347
348 $object = new Societe($this->db);
349 $result = $object->fetch($id, $ref);
350 if (!$result) {
351 throw new RestException(404, 'Thirdparty not found');
352 }
353
354 $upload_dir = $conf->societe->multidir_output[$object->entity]."/".$object->id;
355 } elseif ($modulepart == 'user') {
356 require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
357
358 // Can get doc if has permission to read all user or if it is user itself
359 if (!DolibarrApiAccess::$user->rights->user->user->lire && DolibarrApiAccess::$user->id != $id) {
360 throw new RestException(401);
361 }
362
363 $object = new User($this->db);
364 $result = $object->fetch($id, $ref);
365 if (!$result) {
366 throw new RestException(404, 'User not found');
367 }
368
369 $upload_dir = $conf->user->dir_output.'/'.get_exdir(0, 0, 0, 0, $object, 'user').'/'.$object->id;
370 } elseif ($modulepart == 'adherent' || $modulepart == 'member') {
371 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
372
373 if (!DolibarrApiAccess::$user->rights->adherent->lire) {
374 throw new RestException(401);
375 }
376
377 $object = new Adherent($this->db);
378 $result = $object->fetch($id, $ref);
379 if (!$result) {
380 throw new RestException(404, 'Member not found');
381 }
382
383 $upload_dir = $conf->adherent->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'member');
384 } elseif ($modulepart == 'propal' || $modulepart == 'proposal') {
385 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
386
387 if (!DolibarrApiAccess::$user->hasRight('propal', 'lire')) {
388 throw new RestException(401);
389 }
390
391 $object = new Propal($this->db);
392 $result = $object->fetch($id, $ref);
393 if (!$result) {
394 throw new RestException(404, 'Proposal not found');
395 }
396
397 $upload_dir = $conf->propal->multidir_output[$object->entity]."/".get_exdir(0, 0, 0, 1, $object, 'propal');
398 } elseif ($modulepart == 'supplier_proposal') {
399 require_once DOL_DOCUMENT_ROOT.'/supplier_proposal/class/supplier_proposal.class.php';
400
401 if (!DolibarrApiAccess::$user->rights->supplier_proposal->read) {
402 throw new RestException(401);
403 }
404
405 $object = new Propal($this->db);
406 $result = $object->fetch($id, $ref);
407 if (!$result) {
408 throw new RestException(404, 'Supplier proposal not found');
409 }
410
411 $upload_dir = $conf->propal->multidir_output[$object->entity]."/".get_exdir(0, 0, 0, 1, $object, 'propal');
412 } elseif ($modulepart == 'commande' || $modulepart == 'order') {
413 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
414
415 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
416 throw new RestException(401);
417 }
418
419 $object = new Commande($this->db);
420 $result = $object->fetch($id, $ref);
421 if (!$result) {
422 throw new RestException(404, 'Order not found');
423 }
424
425 $upload_dir = $conf->commande->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'commande');
426 } elseif ($modulepart == 'commande_fournisseur' || $modulepart == 'supplier_order') {
427 $modulepart = 'supplier_order';
428
429 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
430
431 if (empty(DolibarrApiAccess::$user->rights->fournisseur->commande->lire) && empty(DolibarrApiAccess::$user->rights->supplier_order->lire)) {
432 throw new RestException(401);
433 }
434
435 $object = new CommandeFournisseur($this->db);
436 $result = $object->fetch($id, $ref);
437 if (!$result) {
438 throw new RestException(404, 'Purchase order not found');
439 }
440
441 $upload_dir = $conf->fournisseur->dir_output."/commande/".dol_sanitizeFileName($object->ref);
442 } elseif ($modulepart == 'shipment' || $modulepart == 'expedition') {
443 require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
444
445 if (!DolibarrApiAccess::$user->rights->expedition->lire) {
446 throw new RestException(401);
447 }
448
449 $object = new Expedition($this->db);
450 $result = $object->fetch($id, $ref);
451 if (!$result) {
452 throw new RestException(404, 'Shipment not found');
453 }
454
455 $upload_dir = $conf->expedition->dir_output."/sending/".get_exdir(0, 0, 0, 1, $object, 'shipment');
456 } elseif ($modulepart == 'facture' || $modulepart == 'invoice') {
457 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
458
459 if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
460 throw new RestException(401);
461 }
462
463 $object = new Facture($this->db);
464 $result = $object->fetch($id, $ref);
465 if (!$result) {
466 throw new RestException(404, 'Invoice not found');
467 }
468
469 $upload_dir = $conf->facture->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'invoice');
470 } elseif ($modulepart == 'facture_fournisseur' || $modulepart == 'supplier_invoice') {
471 $modulepart = 'supplier_invoice';
472
473 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
474
475 if (empty(DolibarrApiAccess::$user->rights->fournisseur->facture->lire) && empty(DolibarrApiAccess::$user->rights->supplier_invoice->lire)) {
476 throw new RestException(401);
477 }
478
479 $object = new FactureFournisseur($this->db);
480 $result = $object->fetch($id, $ref);
481 if (!$result) {
482 throw new RestException(404, 'Invoice not found');
483 }
484
485 $upload_dir = $conf->fournisseur->dir_output."/facture/".get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier').dol_sanitizeFileName($object->ref);
486 } elseif ($modulepart == 'produit' || $modulepart == 'product') {
487 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
488
489 if (!DolibarrApiAccess::$user->rights->produit->lire) {
490 throw new RestException(401);
491 }
492
493 $object = new Product($this->db);
494 $result = $object->fetch($id, $ref);
495 if ($result == 0) {
496 throw new RestException(404, 'Product not found');
497 } elseif ($result < 0) {
498 throw new RestException(500, 'Error while fetching object: '.$object->error);
499 }
500
501 $upload_dir = $conf->product->multidir_output[$object->entity].'/'.get_exdir(0, 0, 0, 1, $object, 'product');
502 } elseif ($modulepart == 'agenda' || $modulepart == 'action' || $modulepart == 'event') {
503 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
504
505 if (!DolibarrApiAccess::$user->rights->agenda->myactions->read && !DolibarrApiAccess::$user->rights->agenda->allactions->read) {
506 throw new RestException(401);
507 }
508
509 $object = new ActionComm($this->db);
510 $result = $object->fetch($id, $ref);
511 if (!$result) {
512 throw new RestException(404, 'Event not found');
513 }
514
515 $upload_dir = $conf->agenda->dir_output.'/'.dol_sanitizeFileName($object->ref);
516 } elseif ($modulepart == 'expensereport') {
517 require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
518
519 if (!DolibarrApiAccess::$user->rights->expensereport->lire) {
520 throw new RestException(401);
521 }
522
523 $object = new ExpenseReport($this->db);
524 $result = $object->fetch($id, $ref);
525 if (!$result) {
526 throw new RestException(404, 'Expense report not found');
527 }
528
529 $upload_dir = $conf->expensereport->dir_output.'/'.dol_sanitizeFileName($object->ref);
530 } elseif ($modulepart == 'knowledgemanagement') {
531 require_once DOL_DOCUMENT_ROOT.'/knowledgemanagement/class/knowledgerecord.class.php';
532
533 if (!DolibarrApiAccess::$user->hasRight('knowledgemanagement', 'knowledgerecord', 'read') && !DolibarrApiAccess::$user->hasRight('knowledgemanagement', 'knowledgerecord', 'read')) {
534 throw new RestException(401);
535 }
536
537 $object = new KnowledgeRecord($this->db);
538 $result = $object->fetch($id, $ref);
539 if (!$result) {
540 throw new RestException(404, 'KM article not found');
541 }
542
543 $upload_dir = $conf->knowledgemanagement->dir_output.'/knowledgerecord/'.dol_sanitizeFileName($object->ref);
544 } elseif ($modulepart == 'categorie' || $modulepart == 'category') {
545 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
546
547 if (!DolibarrApiAccess::$user->rights->categorie->lire) {
548 throw new RestException(401);
549 }
550
551 $object = new Categorie($this->db);
552 $result = $object->fetch($id, $ref);
553 if (!$result) {
554 throw new RestException(404, 'Category not found');
555 }
556
557 $upload_dir = $conf->categorie->multidir_output[$object->entity].'/'.get_exdir($object->id, 2, 0, 0, $object, 'category').$object->id."/photos/".dol_sanitizeFileName($object->ref);
558 } elseif ($modulepart == 'ecm') {
559 throw new RestException(500, 'Modulepart Ecm not implemented yet.');
560 // // require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmdirectory.class.php';
561
562 // if (!DolibarrApiAccess::$user->rights->ecm->read) {
563 // throw new RestException(401);
564 // }
565
566 // // $object = new EcmDirectory($this->db);
567 // // $result = $object->fetch($ref);
568 // // if (!$result) {
569 // // throw new RestException(404, 'EcmDirectory not found');
570 // // }
571 // $upload_dir = $conf->ecm->dir_output;
572 // $type = 'all';
573 // $recursive = 0;
574 } elseif ($modulepart == 'contrat' || $modulepart == 'contract') {
575 $modulepart = 'contrat';
576 require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
577
578 $object = new Contrat($this->db);
579 $result = $object->fetch($id, $ref);
580 if (!$result) {
581 throw new RestException(404, 'Contract not found');
582 }
583
584 $upload_dir = $conf->contrat->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'contract');
585 } elseif ($modulepart == 'projet' || $modulepart == 'project') {
586 $modulepart = 'project';
587 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
588
589 $object = new Project($this->db);
590 $result = $object->fetch($id, $ref);
591 if (!$result) {
592 throw new RestException(404, 'Project not found');
593 }
594
595 $upload_dir = $conf->projet->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'project');
596 } else {
597 throw new RestException(500, 'Modulepart '.$modulepart.' not implemented yet.');
598 }
599
600 $objectType = $modulepart;
601 if (! empty($object->id) && ! empty($object->table_element)) {
602 $objectType = $object->table_element;
603 }
604
605 $filearray = dol_dir_list($upload_dir, $type, $recursive, '', '(\.meta|_preview.*\.png)$', $sortfield, (strtolower($sortorder) == 'desc' ?SORT_DESC:SORT_ASC), 1);
606 if (empty($filearray)) {
607 throw new RestException(404, 'Search for modulepart '.$modulepart.' with Id '.$object->id.(!empty($object->ref) ? ' or Ref '.$object->ref : '').' does not return any document.');
608 } else {
609 if (($object->id) > 0 && !empty($modulepart)) {
610 require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
611 $ecmfile = new EcmFiles($this->db);
612 $result = $ecmfile->fetchAll('', '', 0, 0, array('t.src_object_type' => $objectType, 't.src_object_id' => $object->id));
613 if ($result < 0) {
614 throw new RestException(503, 'Error when retrieve ecm list : '.$this->db->lasterror());
615 } elseif (is_array($ecmfile->lines) && count($ecmfile->lines) > 0) {
616 $count = count($filearray);
617 for ($i = 0 ; $i < $count ; $i++) {
618 foreach ($ecmfile->lines as $line) {
619 if ($filearray[$i]['name'] == $line->filename) {
620 $filearray[$i] = array_merge($filearray[$i], (array) $line);
621 }
622 }
623 }
624 }
625 }
626 }
627
628 return $filearray;
629 }
630
631
640 /*
641 public function get($id) {
642 return array('note'=>'xxx');
643 }*/
644
645
672 public function post($filename, $modulepart, $ref = '', $subdir = '', $filecontent = '', $fileencoding = '', $overwriteifexists = 0, $createdirifnotexists = 1)
673 {
674 global $db, $conf;
675
676 //var_dump($modulepart);
677 //var_dump($filename);
678 //var_dump($filecontent);exit;
679
680 $modulepartorig = $modulepart;
681
682 if (empty($modulepart)) {
683 throw new RestException(400, 'Modulepart not provided.');
684 }
685
686 if (!DolibarrApiAccess::$user->rights->ecm->upload) {
687 throw new RestException(401);
688 }
689
690 $newfilecontent = '';
691 if (empty($fileencoding)) {
692 $newfilecontent = $filecontent;
693 }
694 if ($fileencoding == 'base64') {
695 $newfilecontent = base64_decode($filecontent);
696 }
697
698 $original_file = dol_sanitizeFileName($filename);
699
700 // Define $uploadir
701 $object = null;
702 $entity = DolibarrApiAccess::$user->entity;
703 if (empty($entity)) {
704 $entity = 1;
705 }
706
707 if ($ref) {
708 $tmpreldir = '';
709 $fetchbyid = false;
710
711 if ($modulepart == 'facture' || $modulepart == 'invoice') {
712 $modulepart = 'facture';
713
714 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
715 $object = new Facture($this->db);
716 } elseif ($modulepart == 'facture_fournisseur' || $modulepart == 'supplier_invoice') {
717 $modulepart = 'supplier_invoice';
718
719 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
720 $object = new FactureFournisseur($this->db);
721 } elseif ($modulepart == 'commande' || $modulepart == 'order') {
722 $modulepart = 'commande';
723
724 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
725 $object = new Commande($this->db);
726 } elseif ($modulepart == 'commande_fournisseur' || $modulepart == 'supplier_order') {
727 $modulepart = 'supplier_order';
728
729 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
730 $object = new CommandeFournisseur($this->db);
731 } elseif ($modulepart == 'projet' || $modulepart == 'project') {
732 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
733 $object = new Project($this->db);
734 } elseif ($modulepart == 'task' || $modulepart == 'project_task') {
735 $modulepart = 'project_task';
736
737 require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
738 $object = new Task($this->db);
739
740 $task_result = $object->fetch('', $ref);
741
742 // Fetching the tasks project is required because its out_dir might be a sub-directory of the project
743 if ($task_result > 0) {
744 $project_result = $object->fetch_projet();
745
746 if ($project_result >= 0) {
747 $tmpreldir = dol_sanitizeFileName($object->project->ref).'/';
748 }
749 } else {
750 throw new RestException(500, 'Error while fetching Task '.$ref);
751 }
752 } elseif ($modulepart == 'product' || $modulepart == 'produit' || $modulepart == 'service' || $modulepart == 'produit|service') {
753 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
754 $object = new Product($this->db);
755 } elseif ($modulepart == 'expensereport') {
756 require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
757 $object = new ExpenseReport($this->db);
758 } elseif ($modulepart == 'fichinter') {
759 require_once DOL_DOCUMENT_ROOT.'/fichinter/class/fichinter.class.php';
760 $object = new Fichinter($this->db);
761 } elseif ($modulepart == 'adherent' || $modulepart == 'member') {
762 $modulepart = 'adherent';
763 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
764 $object = new Adherent($this->db);
765 } elseif ($modulepart == 'proposal' || $modulepart == 'propal' || $modulepart == 'propale') {
766 $modulepart = 'propale';
767 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
768 $object = new Propal($this->db);
769 } elseif ($modulepart == 'agenda' || $modulepart == 'action' || $modulepart == 'event') {
770 $modulepart = 'agenda';
771 require_once DOL_DOCUMENT_ROOT . '/comm/action/class/actioncomm.class.php';
772 $object = new ActionComm($this->db);
773 } elseif ($modulepart == 'contact' || $modulepart == 'socpeople') {
774 $modulepart = 'contact';
775 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
776 $object = new Contact($this->db);
777 $fetchbyid = true;
778 } elseif ($modulepart == 'contrat' || $modulepart == 'contract') {
779 $modulepart = 'contrat';
780 require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
781 $object = new Contrat($this->db);
782 } else {
783 // TODO Implement additional moduleparts
784 throw new RestException(500, 'Modulepart '.$modulepart.' not implemented yet.');
785 }
786
787 if (is_object($object)) {
788 if ($fetchbyid) {
789 $result = $object->fetch($ref);
790 } else {
791 $result = $object->fetch('', $ref);
792 }
793
794 if ($result == 0) {
795 throw new RestException(404, "Object with ref '".$ref."' was not found.");
796 } elseif ($result < 0) {
797 throw new RestException(500, 'Error while fetching object: '.$object->error);
798 }
799 }
800
801 if (!($object->id > 0)) {
802 throw new RestException(404, 'The object '.$modulepart." with ref '".$ref."' was not found.");
803 }
804
805 // Special cases that need to use get_exdir to get real dir of object
806 // In future, all object should use this to define path of documents.
807 if ($modulepart == 'supplier_invoice') {
808 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
809 }
810
811 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref);
812
813 $tmp = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, $ref, 'write');
814 $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
815
816 if (empty($upload_dir) || $upload_dir == '/') {
817 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.');
818 }
819 } else {
820 if ($modulepart == 'invoice') {
821 $modulepart = 'facture';
822 }
823 if ($modulepart == 'member') {
824 $modulepart = 'adherent';
825 }
826
827 $relativefile = $subdir;
828 $tmp = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'write');
829 $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
830
831 if (empty($upload_dir) || $upload_dir == '/') {
832 if (!empty($tmp['error'])) {
833 throw new RestException(401, 'Error returned by dol_check_secure_access_document: '.$tmp['error']);
834 } else {
835 throw new RestException(500, 'This value of modulepart ('.$modulepart.') is not allowed with this value of subdir ('.$relativefile.')');
836 }
837 }
838 }
839 // $original_file here is still value of filename without any dir.
840
841 $upload_dir = dol_sanitizePathName($upload_dir);
842
843 if (!empty($createdirifnotexists)) {
844 if (dol_mkdir($upload_dir) < 0) { // needed by products
845 throw new RestException(500, 'Error while trying to create directory '.$upload_dir);
846 }
847 }
848
849 $destfile = $upload_dir.'/'.$original_file;
850 $destfiletmp = DOL_DATA_ROOT.'/admin/temp/'.$original_file;
851 dol_delete_file($destfiletmp);
852 //var_dump($original_file);exit;
853
854 if (!dol_is_dir(dirname($destfile))) {
855 throw new RestException(401, 'Directory not exists : '.dirname($destfile));
856 }
857
858 if (!$overwriteifexists && dol_is_file($destfile)) {
859 throw new RestException(500, "File with name '".$original_file."' already exists.");
860 }
861
862 // in case temporary directory admin/temp doesn't exist
863 if (!dol_is_dir(dirname($destfiletmp))) {
864 dol_mkdir(dirname($destfiletmp));
865 }
866
867 $fhandle = @fopen($destfiletmp, 'w');
868 if ($fhandle) {
869 $nbofbyteswrote = fwrite($fhandle, $newfilecontent);
870 fclose($fhandle);
871 dolChmod($destfiletmp);
872 } else {
873 throw new RestException(500, "Failed to open file '".$destfiletmp."' for write");
874 }
875
876 $disablevirusscan = 0;
877 $src_file = $destfiletmp;
878 $dest_file = $destfile;
879
880 // Security:
881 // If we need to make a virus scan
882 if (empty($disablevirusscan) && file_exists($src_file)) {
883 $checkvirusarray = dolCheckVirus($src_file);
884 if (count($checkvirusarray)) {
885 dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: errors='.join(',', $checkvirusarray), LOG_WARNING);
886 throw new RestException(500, 'ErrorFileIsInfectedWithAVirus: '.join(',', $checkvirusarray));
887 }
888 }
889
890 // Security:
891 // Disallow file with some extensions. We rename them.
892 // Because if we put the documents directory into a directory inside web root (very bad), this allows to execute on demand arbitrary code.
893 if (isAFileWithExecutableContent($dest_file) && empty($conf->global->MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED)) {
894 // $upload_dir ends with a slash, so be must be sure the medias dir to compare to ends with slash too.
895 $publicmediasdirwithslash = $conf->medias->multidir_output[$conf->entity];
896 if (!preg_match('/\/$/', $publicmediasdirwithslash)) {
897 $publicmediasdirwithslash .= '/';
898 }
899
900 if (strpos($upload_dir, $publicmediasdirwithslash) !== 0 || !getDolGlobalInt("MAIN_DOCUMENT_DISABLE_NOEXE_IN_MEDIAS_DIR")) { // We never add .noexe on files into media directory
901 $dest_file .= '.noexe';
902 }
903 }
904
905 // Security:
906 // We refuse cache files/dirs, upload using .. and pipes into filenames.
907 if (preg_match('/^\./', basename($src_file)) || preg_match('/\.\./', $src_file) || preg_match('/[<>|]/', $src_file)) {
908 dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING);
909 throw new RestException(500, "Refused to deliver file ".$src_file);
910 }
911
912 // Security:
913 // We refuse cache files/dirs, upload using .. and pipes into filenames.
914 if (preg_match('/^\./', basename($dest_file)) || preg_match('/\.\./', $dest_file) || preg_match('/[<>|]/', $dest_file)) {
915 dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING);
916 throw new RestException(500, "Refused to deliver file ".$dest_file);
917 }
918
919 $moreinfo = array('note_private' => 'File uploaded using API /documents from IP '.getUserRemoteIP());
920 if (!empty($object) && is_object($object) && $object->id > 0) {
921 $moreinfo['src_object_type'] = $object->table_element;
922 $moreinfo['src_object_id'] = $object->id;
923 }
924
925 // Move the temporary file at its final emplacement
926 $result = dol_move($destfiletmp, $dest_file, 0, $overwriteifexists, 1, 1, $moreinfo);
927 if (!$result) {
928 throw new RestException(500, "Failed to move file into '".$dest_file."'");
929 }
930
931 return dol_basename($destfile);
932 }
933
947 public function delete($modulepart, $original_file)
948 {
949 global $conf, $langs;
950
951 if (empty($modulepart)) {
952 throw new RestException(400, 'bad value for parameter modulepart');
953 }
954 if (empty($original_file)) {
955 throw new RestException(400, 'bad value for parameter original_file');
956 }
957
958 //--- Finds and returns the document
959 $entity = $conf->entity;
960
961 // Special cases that need to use get_exdir to get real dir of object
962 // If future, all object should use this to define path of documents.
963 /*
964 $tmpreldir = '';
965 if ($modulepart == 'supplier_invoice') {
966 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
967 }
968
969 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref); */
970 $relativefile = $original_file;
971
972 $check_access = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'read');
973 $accessallowed = $check_access['accessallowed'];
974 $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals'];
975 $original_file = $check_access['original_file'];
976
977 if (preg_match('/\.\./', $original_file) || preg_match('/[<>|]/', $original_file)) {
978 throw new RestException(401);
979 }
980 if (!$accessallowed) {
981 throw new RestException(401);
982 }
983
984 if (DolibarrApiAccess::$user->socid > 0) {
985 if ($sqlprotectagainstexternals) {
986 $resql = $this->db->query($sqlprotectagainstexternals);
987 if ($resql) {
988 $num = $this->db->num_rows($resql);
989 $i = 0;
990 while ($i < $num) {
991 $obj = $this->db->fetch_object($resql);
992 if (DolibarrApiAccess::$user->socid != $obj->fk_soc) {
993 throw new RestException(403, 'Not allowed to download documents with such a ref');
994 }
995 $i++;
996 }
997 }
998 }
999 }
1000
1001 $filename = basename($original_file);
1002 $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset
1003
1004 if (!file_exists($original_file_osencoded)) {
1005 dol_syslog("Try to download not found file ".$original_file_osencoded, LOG_WARNING);
1006 throw new RestException(404, 'File not found');
1007 }
1008
1009 if (@unlink($original_file_osencoded)) {
1010 return array(
1011 'success' => array(
1012 'code' => 200,
1013 'message' => 'Document deleted'
1014 )
1015 );
1016 }
1017
1018 throw new RestException(401);
1019 }
1020
1021 // phpcs:disable PEAR.NamingConventions.ValidFunctionName
1029 private function _validate_file($data)
1030 {
1031 // phpcs:enable
1032 $result = array();
1033 foreach (Documents::$DOCUMENT_FIELDS as $field) {
1034 if (!isset($data[$field])) {
1035 throw new RestException(400, "$field field missing");
1036 }
1037 $result[$field] = $data[$field];
1038 }
1039 return $result;
1040 }
1041}
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:32
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.
Class to manage translations.
Class to manage Dolibarr users.
dolCheckVirus($src_file)
Check virus into a file.
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.
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.
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...
dol_is_file($pathoffile)
Return if path is a file.
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.
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)