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