dolibarr 19.0.4
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.'/api/class/api.class.php';
27require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
28
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;
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 = !getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS') ? 0 : 1;
220 $hidedesc = !getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DESC') ? 0 : 1;
221 $hideref = !getDolGlobalString('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 $tmpobject = new Facture($this->db);
228 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
229 if (!$result) {
230 throw new RestException(404, 'Invoice not found');
231 }
232
233 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
234 $result = $tmpobject->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 $tmpobject = new FactureFournisseur($this->db);
241 $result = $tmpobject->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 : $tmpobject->model_pdf;
247 $result = $tmpobject->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 $tmpobject = new Commande($this->db);
254 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
255 if (!$result) {
256 throw new RestException(404, 'Order not found');
257 }
258 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
259 $result = $tmpobject->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 $tmpobject = new Propal($this->db);
266 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
267 if (!$result) {
268 throw new RestException(404, 'Proposal not found');
269 }
270 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
271 $result = $tmpobject->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 $tmpobject = new Contrat($this->db);
279 $result = $tmpobject->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 : $tmpobject->model_pdf;
286 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
287
288 if ($result <= 0) {
289 throw new RestException(500, 'Error generating document missing doctemplate parameter');
290 }
291 } elseif ($modulepart == 'expedition' || $modulepart == 'shipment') {
292 require_once DOL_DOCUMENT_ROOT . '/expedition/class/expedition.class.php';
293
294 $tmpobject = new Expedition($this->db);
295 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
296
297 if (!$result) {
298 throw new RestException(404, 'Shipment not found');
299 }
300
301 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
302 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
303
304 if ($result <= 0) {
305 throw new RestException(500, 'Error generating document missing doctemplate parameter');
306 }
307 } else {
308 throw new RestException(403, 'Generation not available for this modulepart');
309 }
310
311 $filename = basename($original_file);
312 $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset
313
314 if (!file_exists($original_file_osencoded)) {
315 throw new RestException(404, 'File not found');
316 }
317
318 $file_content = file_get_contents($original_file_osencoded);
319 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');
320 }
321
341 public function getDocumentsListByElement($modulepart, $id = 0, $ref = '', $sortfield = '', $sortorder = '')
342 {
343 global $conf;
344
345 if (empty($modulepart)) {
346 throw new RestException(400, 'bad value for parameter modulepart');
347 }
348
349 if (empty($id) && empty($ref)) {
350 throw new RestException(400, 'bad value for parameter id or ref');
351 }
352
353 $id = (empty($id) ? 0 : $id);
354 $recursive = 0;
355 $type = 'files';
356
357 if ($modulepart == 'societe' || $modulepart == 'thirdparty') {
358 require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
359
360 if (!DolibarrApiAccess::$user->hasRight('societe', 'lire')) {
361 throw new RestException(401);
362 }
363
364 $object = new Societe($this->db);
365 $result = $object->fetch($id, $ref);
366 if (!$result) {
367 throw new RestException(404, 'Thirdparty not found');
368 }
369
370 $upload_dir = $conf->societe->multidir_output[$object->entity]."/".$object->id;
371 } elseif ($modulepart == 'user') {
372 require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
373
374 // Can get doc if has permission to read all user or if it is user itself
375 if (!DolibarrApiAccess::$user->rights->user->user->lire && DolibarrApiAccess::$user->id != $id) {
376 throw new RestException(401);
377 }
378
379 $object = new User($this->db);
380 $result = $object->fetch($id, $ref);
381 if (!$result) {
382 throw new RestException(404, 'User not found');
383 }
384
385 $upload_dir = $conf->user->dir_output.'/'.get_exdir(0, 0, 0, 0, $object, 'user').'/'.$object->id;
386 } elseif ($modulepart == 'adherent' || $modulepart == 'member') {
387 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
388
389 if (!DolibarrApiAccess::$user->rights->adherent->lire) {
390 throw new RestException(401);
391 }
392
393 $object = new Adherent($this->db);
394 $result = $object->fetch($id, $ref);
395 if (!$result) {
396 throw new RestException(404, 'Member not found');
397 }
398
399 $upload_dir = $conf->adherent->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'member');
400 } elseif ($modulepart == 'propal' || $modulepart == 'proposal') {
401 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
402
403 if (!DolibarrApiAccess::$user->hasRight('propal', 'lire')) {
404 throw new RestException(401);
405 }
406
407 $object = new Propal($this->db);
408 $result = $object->fetch($id, $ref);
409 if (!$result) {
410 throw new RestException(404, 'Proposal not found');
411 }
412
413 $upload_dir = $conf->propal->multidir_output[$object->entity]."/".get_exdir(0, 0, 0, 1, $object, 'propal');
414 } elseif ($modulepart == 'supplier_proposal') {
415 require_once DOL_DOCUMENT_ROOT.'/supplier_proposal/class/supplier_proposal.class.php';
416
417 if (!DolibarrApiAccess::$user->rights->supplier_proposal->read) {
418 throw new RestException(401);
419 }
420
421 $object = new Propal($this->db);
422 $result = $object->fetch($id, $ref);
423 if (!$result) {
424 throw new RestException(404, 'Supplier proposal not found');
425 }
426
427 $upload_dir = $conf->propal->multidir_output[$object->entity]."/".get_exdir(0, 0, 0, 1, $object, 'propal');
428 } elseif ($modulepart == 'commande' || $modulepart == 'order') {
429 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
430
431 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
432 throw new RestException(401);
433 }
434
435 $object = new Commande($this->db);
436 $result = $object->fetch($id, $ref);
437 if (!$result) {
438 throw new RestException(404, 'Order not found');
439 }
440
441 $upload_dir = $conf->commande->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'commande');
442 } elseif ($modulepart == 'commande_fournisseur' || $modulepart == 'supplier_order') {
443 $modulepart = 'supplier_order';
444
445 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
446
447 if (empty(DolibarrApiAccess::$user->rights->fournisseur->commande->lire) && empty(DolibarrApiAccess::$user->rights->supplier_order->lire)) {
448 throw new RestException(401);
449 }
450
451 $object = new CommandeFournisseur($this->db);
452 $result = $object->fetch($id, $ref);
453 if (!$result) {
454 throw new RestException(404, 'Purchase order not found');
455 }
456
457 $upload_dir = $conf->fournisseur->dir_output."/commande/".dol_sanitizeFileName($object->ref);
458 } elseif ($modulepart == 'shipment' || $modulepart == 'expedition') {
459 require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
460
461 if (!DolibarrApiAccess::$user->rights->expedition->lire) {
462 throw new RestException(401);
463 }
464
465 $object = new Expedition($this->db);
466 $result = $object->fetch($id, $ref);
467 if (!$result) {
468 throw new RestException(404, 'Shipment not found');
469 }
470
471 $upload_dir = $conf->expedition->dir_output."/sending/".get_exdir(0, 0, 0, 1, $object, 'shipment');
472 } elseif ($modulepart == 'facture' || $modulepart == 'invoice') {
473 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
474
475 if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
476 throw new RestException(401);
477 }
478
479 $object = new Facture($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->facture->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'invoice');
486 } elseif ($modulepart == 'facture_fournisseur' || $modulepart == 'supplier_invoice') {
487 $modulepart = 'supplier_invoice';
488
489 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
490
491 if (empty(DolibarrApiAccess::$user->rights->fournisseur->facture->lire) && empty(DolibarrApiAccess::$user->rights->supplier_invoice->lire)) {
492 throw new RestException(401);
493 }
494
495 $object = new FactureFournisseur($this->db);
496 $result = $object->fetch($id, $ref);
497 if (!$result) {
498 throw new RestException(404, 'Invoice not found');
499 }
500
501 $upload_dir = $conf->fournisseur->dir_output."/facture/".get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier').dol_sanitizeFileName($object->ref);
502 } elseif ($modulepart == 'produit' || $modulepart == 'product') {
503 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
504
505 if (!DolibarrApiAccess::$user->rights->produit->lire) {
506 throw new RestException(401);
507 }
508
509 $object = new Product($this->db);
510 $result = $object->fetch($id, $ref);
511 if ($result == 0) {
512 throw new RestException(404, 'Product not found');
513 } elseif ($result < 0) {
514 throw new RestException(500, 'Error while fetching object: '.$object->error);
515 }
516
517 $upload_dir = $conf->product->multidir_output[$object->entity].'/'.get_exdir(0, 0, 0, 1, $object, 'product');
518 } elseif ($modulepart == 'agenda' || $modulepart == 'action' || $modulepart == 'event') {
519 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
520
521 if (!DolibarrApiAccess::$user->rights->agenda->myactions->read && !DolibarrApiAccess::$user->rights->agenda->allactions->read) {
522 throw new RestException(401);
523 }
524
525 $object = new ActionComm($this->db);
526 $result = $object->fetch($id, $ref);
527 if (!$result) {
528 throw new RestException(404, 'Event not found');
529 }
530
531 $upload_dir = $conf->agenda->dir_output.'/'.dol_sanitizeFileName($object->ref);
532 } elseif ($modulepart == 'expensereport') {
533 require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
534
535 if (!DolibarrApiAccess::$user->rights->expensereport->lire) {
536 throw new RestException(401);
537 }
538
539 $object = new ExpenseReport($this->db);
540 $result = $object->fetch($id, $ref);
541 if (!$result) {
542 throw new RestException(404, 'Expense report not found');
543 }
544
545 $upload_dir = $conf->expensereport->dir_output.'/'.dol_sanitizeFileName($object->ref);
546 } elseif ($modulepart == 'knowledgemanagement') {
547 require_once DOL_DOCUMENT_ROOT.'/knowledgemanagement/class/knowledgerecord.class.php';
548
549 if (!DolibarrApiAccess::$user->hasRight('knowledgemanagement', 'knowledgerecord', 'read') && !DolibarrApiAccess::$user->hasRight('knowledgemanagement', 'knowledgerecord', 'read')) {
550 throw new RestException(401);
551 }
552
553 $object = new KnowledgeRecord($this->db);
554 $result = $object->fetch($id, $ref);
555 if (!$result) {
556 throw new RestException(404, 'KM article not found');
557 }
558
559 $upload_dir = $conf->knowledgemanagement->dir_output.'/knowledgerecord/'.dol_sanitizeFileName($object->ref);
560 } elseif ($modulepart == 'categorie' || $modulepart == 'category') {
561 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
562
563 if (!DolibarrApiAccess::$user->rights->categorie->lire) {
564 throw new RestException(401);
565 }
566
567 $object = new Categorie($this->db);
568 $result = $object->fetch($id, $ref);
569 if (!$result) {
570 throw new RestException(404, 'Category not found');
571 }
572
573 $upload_dir = $conf->categorie->multidir_output[$object->entity].'/'.get_exdir($object->id, 2, 0, 0, $object, 'category').$object->id."/photos/".dol_sanitizeFileName($object->ref);
574 } elseif ($modulepart == 'ecm') {
575 throw new RestException(500, 'Modulepart Ecm not implemented yet.');
576 // require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmdirectory.class.php';
577
578 // if (!DolibarrApiAccess::$user->rights->ecm->read) {
579 // throw new RestException(401);
580 // }
581
582 // // $object = new EcmDirectory($this->db);
583 // // $result = $object->fetch($ref);
584 // // if (!$result) {
585 // // throw new RestException(404, 'EcmDirectory not found');
586 // // }
587 // $upload_dir = $conf->ecm->dir_output;
588 // $type = 'all';
589 // $recursive = 0;
590 } elseif ($modulepart == 'contrat' || $modulepart == 'contract') {
591 $modulepart = 'contrat';
592 require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
593
594 $object = new Contrat($this->db);
595 $result = $object->fetch($id, $ref);
596 if (!$result) {
597 throw new RestException(404, 'Contract not found');
598 }
599
600 $upload_dir = $conf->contrat->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'contract');
601 } elseif ($modulepart == 'projet' || $modulepart == 'project') {
602 $modulepart = 'project';
603 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
604
605 $object = new Project($this->db);
606 $result = $object->fetch($id, $ref);
607 if (!$result) {
608 throw new RestException(404, 'Project not found');
609 }
610
611 $upload_dir = $conf->projet->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'project');
612 } else {
613 throw new RestException(500, 'Modulepart '.$modulepart.' not implemented yet.');
614 }
615
616 $objectType = $modulepart;
617 if (! empty($object->id) && ! empty($object->table_element)) {
618 $objectType = $object->table_element;
619 }
620
621 $filearray = dol_dir_list($upload_dir, $type, $recursive, '', '(\.meta|_preview.*\.png)$', $sortfield, (strtolower($sortorder) == 'desc' ? SORT_DESC : SORT_ASC), 1);
622 if (empty($filearray)) {
623 throw new RestException(404, 'Search for modulepart '.$modulepart.' with Id '.$object->id.(!empty($object->ref) ? ' or Ref '.$object->ref : '').' does not return any document.');
624 } else {
625 if (($object->id) > 0 && !empty($modulepart)) {
626 require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
627 $ecmfile = new EcmFiles($this->db);
628 $result = $ecmfile->fetchAll('', '', 0, 0, array('t.src_object_type' => $objectType, 't.src_object_id' => $object->id));
629 if ($result < 0) {
630 throw new RestException(503, 'Error when retrieve ecm list : '.$this->db->lasterror());
631 } elseif (is_array($ecmfile->lines) && count($ecmfile->lines) > 0) {
632 $count = count($filearray);
633 for ($i = 0 ; $i < $count ; $i++) {
634 foreach ($ecmfile->lines as $line) {
635 if ($filearray[$i]['name'] == $line->filename) {
636 $filearray[$i] = array_merge($filearray[$i], (array) $line);
637 }
638 }
639 }
640 }
641 }
642 }
643
644 return $filearray;
645 }
646
647
656 /*
657 public function get($id) {
658 return array('note'=>'xxx');
659 }*/
660
661
688 public function post($filename, $modulepart, $ref = '', $subdir = '', $filecontent = '', $fileencoding = '', $overwriteifexists = 0, $createdirifnotexists = 1)
689 {
690 global $conf;
691
692 //var_dump($modulepart);
693 //var_dump($filename);
694 //var_dump($filecontent);exit;
695
696 $modulepartorig = $modulepart;
697
698 if (empty($modulepart)) {
699 throw new RestException(400, 'Modulepart not provided.');
700 }
701
702 $newfilecontent = '';
703 if (empty($fileencoding)) {
704 $newfilecontent = $filecontent;
705 }
706 if ($fileencoding == 'base64') {
707 $newfilecontent = base64_decode($filecontent);
708 }
709
710 $original_file = dol_sanitizeFileName($filename);
711
712 // Define $uploadir
713 $object = null;
714 $entity = DolibarrApiAccess::$user->entity;
715 if (empty($entity)) {
716 $entity = 1;
717 }
718
719 if ($ref) {
720 $tmpreldir = '';
721 $fetchbyid = false;
722
723 if ($modulepart == 'facture' || $modulepart == 'invoice') {
724 $modulepart = 'facture';
725
726 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
727 $object = new Facture($this->db);
728 } elseif ($modulepart == 'facture_fournisseur' || $modulepart == 'supplier_invoice') {
729 $modulepart = 'supplier_invoice';
730
731 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
732 $object = new FactureFournisseur($this->db);
733 } elseif ($modulepart == 'commande' || $modulepart == 'order') {
734 $modulepart = 'commande';
735
736 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
737 $object = new Commande($this->db);
738 } elseif ($modulepart == 'commande_fournisseur' || $modulepart == 'supplier_order') {
739 $modulepart = 'supplier_order';
740
741 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
742 $object = new CommandeFournisseur($this->db);
743 } elseif ($modulepart == 'projet' || $modulepart == 'project') {
744 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
745 $object = new Project($this->db);
746 } elseif ($modulepart == 'task' || $modulepart == 'project_task') {
747 $modulepart = 'project_task';
748
749 require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
750 $object = new Task($this->db);
751
752 $task_result = $object->fetch('', $ref);
753
754 // Fetching the tasks project is required because its out_dir might be a sub-directory of the project
755 if ($task_result > 0) {
756 $project_result = $object->fetch_projet();
757
758 if ($project_result >= 0) {
759 $tmpreldir = dol_sanitizeFileName($object->project->ref).'/';
760 }
761 } else {
762 throw new RestException(500, 'Error while fetching Task '.$ref);
763 }
764 } elseif ($modulepart == 'product' || $modulepart == 'produit' || $modulepart == 'service' || $modulepart == 'produit|service') {
765 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
766 $object = new Product($this->db);
767 } elseif ($modulepart == 'expensereport') {
768 require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
769 $object = new ExpenseReport($this->db);
770 } elseif ($modulepart == 'fichinter') {
771 require_once DOL_DOCUMENT_ROOT.'/fichinter/class/fichinter.class.php';
772 $object = new Fichinter($this->db);
773 } elseif ($modulepart == 'adherent' || $modulepart == 'member') {
774 $modulepart = 'adherent';
775 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
776 $object = new Adherent($this->db);
777 } elseif ($modulepart == 'proposal' || $modulepart == 'propal' || $modulepart == 'propale') {
778 $modulepart = 'propale';
779 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
780 $object = new Propal($this->db);
781 } elseif ($modulepart == 'agenda' || $modulepart == 'action' || $modulepart == 'event') {
782 $modulepart = 'agenda';
783 require_once DOL_DOCUMENT_ROOT . '/comm/action/class/actioncomm.class.php';
784 $object = new ActionComm($this->db);
785 } elseif ($modulepart == 'contact' || $modulepart == 'socpeople') {
786 $modulepart = 'contact';
787 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
788 $object = new Contact($this->db);
789 $fetchbyid = true;
790 } elseif ($modulepart == 'contrat' || $modulepart == 'contract') {
791 $modulepart = 'contrat';
792 require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
793 $object = new Contrat($this->db);
794 } else {
795 // TODO Implement additional moduleparts
796 throw new RestException(500, 'Modulepart '.$modulepart.' not implemented yet.');
797 }
798
799 if (is_object($object)) {
800 if ($fetchbyid) {
801 $result = $object->fetch($ref);
802 } else {
803 $result = $object->fetch('', $ref);
804 }
805
806 if ($result == 0) {
807 throw new RestException(404, "Object with ref '".$ref."' was not found.");
808 } elseif ($result < 0) {
809 throw new RestException(500, 'Error while fetching object: '.$object->error);
810 }
811 }
812
813 if (!($object->id > 0)) {
814 throw new RestException(404, 'The object '.$modulepart." with ref '".$ref."' was not found.");
815 }
816
817 // Special cases that need to use get_exdir to get real dir of object
818 // In future, all object should use this to define path of documents.
819 if ($modulepart == 'supplier_invoice') {
820 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
821 }
822
823 // Test on permissions
824 if ($modulepart != 'ecm') {
825 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref);
826 $tmp = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, $ref, 'write');
827 $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
828 } else {
829 if (!DolibarrApiAccess::$user->hasRight('ecm', 'upload')) {
830 throw new RestException(401, 'Missing permission to upload files in ECM module');
831 }
832 $upload_dir = $conf->medias->multidir_output[$conf->entity];
833 }
834
835 if (empty($upload_dir) || $upload_dir == '/') {
836 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.');
837 }
838 } else {
839 if ($modulepart == 'invoice') {
840 $modulepart = 'facture';
841 }
842 if ($modulepart == 'member') {
843 $modulepart = 'adherent';
844 }
845
846 // Test on permissions
847 if ($modulepart != 'ecm') {
848 $relativefile = $subdir;
849 $tmp = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'write');
850 $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
851 } else {
852 if (!DolibarrApiAccess::$user->hasRight('ecm', 'upload')) {
853 throw new RestException(401, 'Missing permission to upload files in ECM module');
854 }
855 $upload_dir = $conf->medias->multidir_output[$conf->entity];
856 }
857
858 if (empty($upload_dir) || $upload_dir == '/') {
859 if (!empty($tmp['error'])) {
860 throw new RestException(401, 'Error returned by dol_check_secure_access_document: '.$tmp['error']);
861 } else {
862 throw new RestException(500, 'This value of modulepart ('.$modulepart.') is not allowed with this value of subdir ('.$relativefile.')');
863 }
864 }
865 }
866 // $original_file here is still value of filename without any dir.
867
868 $upload_dir = dol_sanitizePathName($upload_dir);
869
870 if (!empty($createdirifnotexists)) {
871 if (dol_mkdir($upload_dir) < 0) { // needed by products
872 throw new RestException(500, 'Error while trying to create directory '.$upload_dir);
873 }
874 }
875
876 $destfile = $upload_dir.'/'.$original_file;
877 $destfiletmp = DOL_DATA_ROOT.'/admin/temp/'.$original_file;
878 dol_delete_file($destfiletmp);
879 //var_dump($original_file);exit;
880
881 if (!dol_is_dir(dirname($destfile))) {
882 throw new RestException(401, 'Directory not exists : '.dirname($destfile));
883 }
884
885 if (!$overwriteifexists && dol_is_file($destfile)) {
886 throw new RestException(500, "File with name '".$original_file."' already exists.");
887 }
888
889 // in case temporary directory admin/temp doesn't exist
890 if (!dol_is_dir(dirname($destfiletmp))) {
891 dol_mkdir(dirname($destfiletmp));
892 }
893
894 $fhandle = @fopen($destfiletmp, 'w');
895 if ($fhandle) {
896 $nbofbyteswrote = fwrite($fhandle, $newfilecontent);
897 fclose($fhandle);
898 dolChmod($destfiletmp);
899 } else {
900 throw new RestException(500, "Failed to open file '".$destfiletmp."' for write");
901 }
902
903 $disablevirusscan = 0;
904 $src_file = $destfiletmp;
905 $dest_file = $destfile;
906
907 // Security:
908 // If we need to make a virus scan
909 if (empty($disablevirusscan) && file_exists($src_file)) {
910 $checkvirusarray = dolCheckVirus($src_file);
911 if (count($checkvirusarray)) {
912 dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: errors='.join(',', $checkvirusarray), LOG_WARNING);
913 throw new RestException(500, 'ErrorFileIsInfectedWithAVirus: '.join(',', $checkvirusarray));
914 }
915 }
916
917 // Security:
918 // Disallow file with some extensions. We rename them.
919 // Because if we put the documents directory into a directory inside web root (very bad), this allows to execute on demand arbitrary code.
920 if (isAFileWithExecutableContent($dest_file) && !getDolGlobalString('MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED')) {
921 // $upload_dir ends with a slash, so be must be sure the medias dir to compare to ends with slash too.
922 $publicmediasdirwithslash = $conf->medias->multidir_output[$conf->entity];
923 if (!preg_match('/\/$/', $publicmediasdirwithslash)) {
924 $publicmediasdirwithslash .= '/';
925 }
926
927 if (strpos($upload_dir, $publicmediasdirwithslash) !== 0 || !getDolGlobalInt("MAIN_DOCUMENT_DISABLE_NOEXE_IN_MEDIAS_DIR")) { // We never add .noexe on files into media directory
928 $dest_file .= '.noexe';
929 }
930 }
931
932 // Security:
933 // We refuse cache files/dirs, upload using .. and pipes into filenames.
934 if (preg_match('/^\./', basename($src_file)) || preg_match('/\.\./', $src_file) || preg_match('/[<>|]/', $src_file)) {
935 dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING);
936 throw new RestException(500, "Refused to deliver file ".$src_file);
937 }
938
939 // Security:
940 // We refuse cache files/dirs, upload using .. and pipes into filenames.
941 if (preg_match('/^\./', basename($dest_file)) || preg_match('/\.\./', $dest_file) || preg_match('/[<>|]/', $dest_file)) {
942 dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING);
943 throw new RestException(500, "Refused to deliver file ".$dest_file);
944 }
945
946 $moreinfo = array('note_private' => 'File uploaded using API /documents from IP '.getUserRemoteIP());
947 if (!empty($object) && is_object($object) && $object->id > 0) {
948 $moreinfo['src_object_type'] = $object->table_element;
949 $moreinfo['src_object_id'] = $object->id;
950 }
951
952 // Move the temporary file at its final emplacement
953 $result = dol_move($destfiletmp, $dest_file, 0, $overwriteifexists, 1, 1, $moreinfo);
954 if (!$result) {
955 throw new RestException(500, "Failed to move file into '".$dest_file."'");
956 }
957
958 return dol_basename($destfile);
959 }
960
974 public function delete($modulepart, $original_file)
975 {
976 global $conf, $langs;
977
978 if (empty($modulepart)) {
979 throw new RestException(400, 'bad value for parameter modulepart');
980 }
981 if (empty($original_file)) {
982 throw new RestException(400, 'bad value for parameter original_file');
983 }
984
985 //--- Finds and returns the document
986 $entity = $conf->entity;
987
988 // Special cases that need to use get_exdir to get real dir of object
989 // If future, all object should use this to define path of documents.
990 /*
991 $tmpreldir = '';
992 if ($modulepart == 'supplier_invoice') {
993 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
994 }
995
996 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref); */
997 $relativefile = $original_file;
998
999 $check_access = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'read');
1000 $accessallowed = $check_access['accessallowed'];
1001 $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals'];
1002 $original_file = $check_access['original_file'];
1003
1004 if (preg_match('/\.\./', $original_file) || preg_match('/[<>|]/', $original_file)) {
1005 throw new RestException(401);
1006 }
1007 if (!$accessallowed) {
1008 throw new RestException(401);
1009 }
1010
1011 if (DolibarrApiAccess::$user->socid > 0) {
1012 if ($sqlprotectagainstexternals) {
1013 $resql = $this->db->query($sqlprotectagainstexternals);
1014 if ($resql) {
1015 $num = $this->db->num_rows($resql);
1016 $i = 0;
1017 while ($i < $num) {
1018 $obj = $this->db->fetch_object($resql);
1019 if (DolibarrApiAccess::$user->socid != $obj->fk_soc) {
1020 throw new RestException(403, 'Not allowed to download documents with such a ref');
1021 }
1022 $i++;
1023 }
1024 }
1025 }
1026 }
1027
1028 $filename = basename($original_file);
1029 $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset
1030
1031 if (!file_exists($original_file_osencoded)) {
1032 dol_syslog("Try to download not found file ".$original_file_osencoded, LOG_WARNING);
1033 throw new RestException(404, 'File not found');
1034 }
1035
1036 if (@unlink($original_file_osencoded)) {
1037 return array(
1038 'success' => array(
1039 'code' => 200,
1040 'message' => 'Document deleted'
1041 )
1042 );
1043 }
1044
1045 throw new RestException(401);
1046 }
1047
1048 // phpcs:disable PEAR.NamingConventions.ValidFunctionName
1056 private function _validate_file($data)
1057 {
1058 // phpcs:enable
1059 $result = array();
1060 foreach (Documents::$DOCUMENT_FIELDS as $field) {
1061 if (!isset($data[$field])) {
1062 throw new RestException(400, "$field field missing");
1063 }
1064 $result[$field] = $data[$field];
1065 }
1066 return $result;
1067 }
1068}
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 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 a 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.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
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)
Contact()
Old copy.
Definition index.php:587