PageRenderTime 45ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/htdocs/document.php

https://github.com/asterix14/dolibarr
PHP | 550 lines | 374 code | 70 blank | 106 comment | 203 complexity | 5d666758b2317438cd95b33c9c078611 MD5 | raw file
Possible License(s): LGPL-2.0
  1. <?php
  2. /* Copyright (C) 2004-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  3. * Copyright (C) 2004-2010 Laurent Destailleur <eldy@users.sourceforge.net>
  4. * Copyright (C) 2005 Simon Tosser <simon@kornog-computing.com>
  5. * Copyright (C) 2005-2011 Regis Houssin <regis@dolibarr.fr>
  6. * Copyright (C) 2010 Pierre Morin <pierre.morin@auguria.net>
  7. * Copyright (C) 2010 Juanjo Menent <jmenent@2byte.es>
  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 2 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 <http://www.gnu.org/licenses/>.
  21. * or see http://www.gnu.org/
  22. */
  23. /**
  24. * \file htdocs/document.php
  25. * \brief Wrapper to download data files
  26. * \remarks Call of this wrapper is made with URL:
  27. * document.php?modulepart=repfichierconcerne&file=pathrelatifdufichier
  28. */
  29. define('NOTOKENRENEWAL',1); // Disables token renewal
  30. // Pour autre que bittorrent, on charge environnement + info issus de logon (comme le user)
  31. if (isset($_GET["modulepart"]) && $_GET["modulepart"] == 'bittorrent' && ! defined("NOLOGIN"))
  32. {
  33. define("NOLOGIN",1);
  34. define("NOCSRFCHECK",1); // We accept to go on this page from external web site.
  35. }
  36. if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU','1');
  37. if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML','1');
  38. if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX','1');
  39. /**
  40. * Wrapper, donc header vierge
  41. *
  42. * @return null
  43. */
  44. function llxHeader() { }
  45. require("./main.inc.php"); // Load $user and permissions
  46. require_once(DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php');
  47. $encoding = '';
  48. $action = GETPOST("action");
  49. $original_file = GETPOST("file"); // Do not use urldecode here ($_GET are already decoded by PHP).
  50. $modulepart = GETPOST("modulepart");
  51. $urlsource = GETPOST("urlsource");
  52. // Security check
  53. if (empty($modulepart)) accessforbidden('Bad value for parameter modulepart');
  54. /*
  55. * Action
  56. */
  57. // None
  58. /*
  59. * View
  60. */
  61. // Define mime type
  62. $type = 'application/octet-stream';
  63. if (GETPOST('type')) $type=GETPOST('type');
  64. else $type=dol_mimetype($original_file);
  65. //print 'X'.$type.'-'.$original_file;exit;
  66. // Define attachment (attachment=true to force choice popup 'open'/'save as')
  67. $attachment = true;
  68. // Text files
  69. if (preg_match('/\.txt$/i',$original_file)) { $attachment = false; }
  70. if (preg_match('/\.csv$/i',$original_file)) { $attachment = true; }
  71. if (preg_match('/\.tsv$/i',$original_file)) { $attachment = true; }
  72. // Documents MS office
  73. if (preg_match('/\.doc(x)?$/i',$original_file)) { $attachment = true; }
  74. if (preg_match('/\.dot(x)?$/i',$original_file)) { $attachment = true; }
  75. if (preg_match('/\.mdb$/i',$original_file)) { $attachment = true; }
  76. if (preg_match('/\.ppt(x)?$/i',$original_file)) { $attachment = true; }
  77. if (preg_match('/\.xls(x)?$/i',$original_file)) { $attachment = true; }
  78. // Documents Open office
  79. if (preg_match('/\.odp$/i',$original_file)) { $attachment = true; }
  80. if (preg_match('/\.ods$/i',$original_file)) { $attachment = true; }
  81. if (preg_match('/\.odt$/i',$original_file)) { $attachment = true; }
  82. // Misc
  83. if (preg_match('/\.(html|htm)$/i',$original_file)) { $attachment = false; }
  84. if (preg_match('/\.pdf$/i',$original_file)) { $attachment = true; }
  85. if (preg_match('/\.sql$/i',$original_file)) { $attachment = true; }
  86. // Images
  87. if (preg_match('/\.jpg$/i',$original_file)) { $attachment = true; }
  88. if (preg_match('/\.jpeg$/i',$original_file)) { $attachment = true; }
  89. if (preg_match('/\.png$/i',$original_file)) { $attachment = true; }
  90. if (preg_match('/\.gif$/i',$original_file)) { $attachment = true; }
  91. if (preg_match('/\.bmp$/i',$original_file)) { $attachment = true; }
  92. if (preg_match('/\.tiff$/i',$original_file)) { $attachment = true; }
  93. // Calendar
  94. if (preg_match('/\.vcs$/i',$original_file)) { $attachment = true; }
  95. if (preg_match('/\.ics$/i',$original_file)) { $attachment = true; }
  96. if (GETPOST("attachment")) { $attachment = true; }
  97. if (! empty($conf->global->MAIN_DISABLE_FORCE_SAVEAS)) $attachment=false;
  98. //print "XX".$attachment;exit;
  99. // Suppression de la chaine de caractere ../ dans $original_file
  100. $original_file = str_replace("../","/", $original_file);
  101. // find the subdirectory name as the reference
  102. $refname=basename(dirname($original_file)."/");
  103. // Security check
  104. $accessallowed=0;
  105. $sqlprotectagainstexternals='';
  106. if ($modulepart)
  107. {
  108. // On fait une verification des droits et on definit le repertoire concerne
  109. // Wrapping for third parties
  110. if ($modulepart == 'company')
  111. {
  112. if ($user->rights->societe->lire || preg_match('/^specimen/i',$original_file))
  113. {
  114. $accessallowed=1;
  115. }
  116. $original_file=$conf->societe->dir_output.'/'.$original_file;
  117. $sqlprotectagainstexternals = "SELECT rowid as fk_soc FROM ".MAIN_DB_PREFIX."societe WHERE rowid='".$refname."' AND entity=".$conf->entity;
  118. }
  119. // Wrapping for invoices
  120. else if ($modulepart == 'facture')
  121. {
  122. if ($user->rights->facture->lire || preg_match('/^specimen/i',$original_file))
  123. {
  124. $accessallowed=1;
  125. }
  126. $original_file=$conf->facture->dir_output.'/'.$original_file;
  127. $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture WHERE ref='".$refname."' AND entity=".$conf->entity;
  128. }
  129. else if ($modulepart == 'unpaid')
  130. {
  131. if ($user->rights->facture->lire || preg_match('/^specimen/i',$original_file))
  132. {
  133. $accessallowed=1;
  134. }
  135. $original_file=$conf->facture->dir_output.'/unpaid/temp/'.$original_file;
  136. }
  137. // Wrapping pour les fiches intervention
  138. else if ($modulepart == 'ficheinter')
  139. {
  140. if ($user->rights->ficheinter->lire || preg_match('/^specimen/i',$original_file))
  141. {
  142. $accessallowed=1;
  143. }
  144. $original_file=$conf->ficheinter->dir_output.'/'.$original_file;
  145. $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$refname."' AND entity=".$conf->entity;
  146. }
  147. // Wrapping pour les prelevements
  148. else if ($modulepart == 'prelevement')
  149. {
  150. if ($user->rights->prelevement->bons->lire || preg_match('/^specimen/i',$original_file))
  151. {
  152. $accessallowed=1;
  153. }
  154. $original_file=$conf->prelevement->dir_output.'/'.$original_file;
  155. }
  156. // Wrapping pour les propales
  157. else if ($modulepart == 'propal')
  158. {
  159. if ($user->rights->propale->lire || preg_match('/^specimen/i',$original_file))
  160. {
  161. $accessallowed=1;
  162. }
  163. $original_file=$conf->propale->dir_output.'/'.$original_file;
  164. $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."propal WHERE ref='".$refname."' AND entity=".$conf->entity;
  165. }
  166. // Wrapping pour les commandes
  167. else if ($modulepart == 'commande')
  168. {
  169. if ($user->rights->commande->lire || preg_match('/^specimen/i',$original_file))
  170. {
  171. $accessallowed=1;
  172. }
  173. $original_file=$conf->commande->dir_output.'/'.$original_file;
  174. $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."commande WHERE ref='".$refname."' AND entity=".$conf->entity;
  175. }
  176. // Wrapping pour les projets
  177. else if ($modulepart == 'project')
  178. {
  179. if ($user->rights->projet->lire || preg_match('/^specimen/i',$original_file))
  180. {
  181. $accessallowed=1;
  182. }
  183. $original_file=$conf->projet->dir_output.'/'.$original_file;
  184. $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$refname."' AND entity=".$conf->entity;
  185. }
  186. // Wrapping pour les commandes fournisseurs
  187. else if ($modulepart == 'commande_fournisseur')
  188. {
  189. if ($user->rights->fournisseur->commande->lire || preg_match('/^specimen/i',$original_file))
  190. {
  191. $accessallowed=1;
  192. }
  193. $original_file=$conf->fournisseur->commande->dir_output.'/'.$original_file;
  194. $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."commande_fournisseur WHERE ref='".$refname."' AND entity=".$conf->entity;
  195. }
  196. // Wrapping pour les factures fournisseurs
  197. else if ($modulepart == 'facture_fournisseur' || $modulepart == 'invoice_supplier')
  198. {
  199. if ($user->rights->fournisseur->facture->lire || preg_match('/^specimen/i',$original_file))
  200. {
  201. $accessallowed=1;
  202. }
  203. $original_file=$conf->fournisseur->facture->dir_output.'/'.$original_file;
  204. $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture_fourn WHERE facnumber='".$refname."' AND entity=".$conf->entity;
  205. }
  206. // Wrapping pour les rapport de paiements
  207. else if ($modulepart == 'facture_paiement')
  208. {
  209. if ($user->rights->facture->lire || preg_match('/^specimen/i',$original_file))
  210. {
  211. $accessallowed=1;
  212. }
  213. if ($user->societe_id > 0) $original_file=$conf->facture->dir_output.'/payments/private/'.$user->id.'/'.$original_file;
  214. else $original_file=$conf->facture->dir_output.'/payments/'.$original_file;
  215. }
  216. // Wrapping pour les exports de compta
  217. else if ($modulepart == 'export_compta')
  218. {
  219. if ($user->rights->compta->ventilation->creer || preg_match('/^specimen/i',$original_file))
  220. {
  221. $accessallowed=1;
  222. }
  223. $original_file=$conf->compta->dir_output.'/'.$original_file;
  224. }
  225. // Wrapping pour les societe
  226. else if ($modulepart == 'societe')
  227. {
  228. if ($user->rights->societe->lire || preg_match('/^specimen/i',$original_file))
  229. {
  230. $accessallowed=1;
  231. }
  232. $original_file=$conf->societe->dir_output.'/'.$original_file;
  233. $sqlprotectagainstexternals = "SELECT rowid as fk_soc FROM ".MAIN_DB_PREFIX."societe WHERE rowid='".$refname."' AND entity=".$conf->entity;
  234. }
  235. // Wrapping pour les expedition
  236. else if ($modulepart == 'expedition')
  237. {
  238. if ($user->rights->expedition->lire || preg_match('/^specimen/i',$original_file))
  239. {
  240. $accessallowed=1;
  241. }
  242. $original_file=$conf->expedition->dir_output."/sending/".$original_file;
  243. }
  244. // Wrapping pour les bons de livraison
  245. else if ($modulepart == 'livraison')
  246. {
  247. if ($user->rights->expedition->livraison->lire || preg_match('/^specimen/i',$original_file))
  248. {
  249. $accessallowed=1;
  250. }
  251. $original_file=$conf->expedition->dir_output."/receipt/".$original_file;
  252. }
  253. // Wrapping pour les actions
  254. else if ($modulepart == 'actions')
  255. {
  256. if ($user->rights->agenda->myactions->read || preg_match('/^specimen/i',$original_file))
  257. {
  258. $accessallowed=1;
  259. }
  260. $original_file=$conf->agenda->dir_output.'/'.$original_file;
  261. }
  262. // Wrapping pour les actions
  263. else if ($modulepart == 'actionsreport')
  264. {
  265. if ($user->rights->agenda->allactions->read || preg_match('/^specimen/i',$original_file))
  266. {
  267. $accessallowed=1;
  268. }
  269. $original_file = $conf->agenda->dir_temp."/".$original_file;
  270. }
  271. // Wrapping pour les produits et services
  272. else if ($modulepart == 'produit' || $modulepart == 'service')
  273. {
  274. if (($user->rights->produit->lire || $user->rights->service->lire) || preg_match('/^specimen/i',$original_file))
  275. {
  276. $accessallowed=1;
  277. }
  278. if ($conf->product->enabled) $original_file=$conf->product->dir_output.'/'.$original_file;
  279. elseif ($conf->service->enabled) $original_file=$conf->service->dir_output.'/'.$original_file;
  280. }
  281. // Wrapping pour les contrats
  282. else if ($modulepart == 'contract')
  283. {
  284. if ($user->rights->contrat->lire || preg_match('/^specimen/i',$original_file))
  285. {
  286. $accessallowed=1;
  287. }
  288. $original_file=$conf->contrat->dir_output.'/'.$original_file;
  289. }
  290. // Wrapping pour les documents generaux
  291. else if ($modulepart == 'ged')
  292. {
  293. if ($user->rights->document->lire)
  294. {
  295. $accessallowed=1;
  296. }
  297. $original_file= $conf->ged->dir_output.'/'.$original_file;
  298. }
  299. // Wrapping pour les dons
  300. else if ($modulepart == 'donation')
  301. {
  302. if ($user->rights->don->lire || preg_match('/^specimen/i',$original_file))
  303. {
  304. $accessallowed=1;
  305. }
  306. $original_file=$conf->don->dir_output.'/'.$original_file;
  307. }
  308. // Wrapping pour les remises de cheques
  309. else if ($modulepart == 'remisecheque')
  310. {
  311. if ($user->rights->banque->lire || preg_match('/^specimen/i',$original_file))
  312. {
  313. $accessallowed=1;
  314. }
  315. $original_file=$conf->banque->dir_output.'/bordereau/'.get_exdir(basename($original_file,".pdf"),2,1).$original_file;
  316. }
  317. // Wrapping for export module
  318. else if ($modulepart == 'export')
  319. {
  320. // Aucun test necessaire car on force le rep de download sur
  321. // le rep export qui est propre a l'utilisateur
  322. $accessallowed=1;
  323. $original_file=$conf->export->dir_temp.'/'.$user->id.'/'.$original_file;
  324. }
  325. // Wrapping for import module
  326. else if ($modulepart == 'import')
  327. {
  328. // Aucun test necessaire car on force le rep de download sur
  329. // le rep export qui est propre a l'utilisateur
  330. $accessallowed=1;
  331. $original_file=$conf->import->dir_temp.'/'.$original_file;
  332. }
  333. // Wrapping pour l'editeur wysiwyg
  334. else if ($modulepart == 'editor')
  335. {
  336. // Aucun test necessaire car on force le rep de download sur
  337. // le rep export qui est propre a l'utilisateur
  338. $accessallowed=1;
  339. $original_file=$conf->fckeditor->dir_output.'/'.$original_file;
  340. }
  341. // Wrapping pour les backups
  342. else if ($modulepart == 'systemtools')
  343. {
  344. if ($user->admin)
  345. {
  346. $accessallowed=1;
  347. }
  348. $original_file=$conf->admin->dir_output.'/'.$original_file;
  349. }
  350. // Wrapping pour BitTorrent
  351. else if ($modulepart == 'bittorrent')
  352. {
  353. $accessallowed=1;
  354. $dir='files';
  355. if ($type == 'application/x-bittorrent') $dir='torrents';
  356. $original_file=$conf->bittorrent->dir_output.'/'.$dir.'/'.$original_file;
  357. }
  358. // Wrapping pour Foundation module
  359. else if ($modulepart == 'member')
  360. {
  361. if ($user->rights->adherent->lire || preg_match('/^specimen/i',$original_file))
  362. {
  363. $accessallowed=1;
  364. }
  365. $original_file=$conf->adherent->dir_output.'/'.$original_file;
  366. }
  367. // Wrapping for Scanner
  368. else if ($modulepart == 'scanner_user_temp')
  369. {
  370. $accessallowed=1;
  371. $original_file=$conf->scanner->dir_temp.'/'.$user->id.'/'.$original_file;
  372. }
  373. // Generic wrapping
  374. else
  375. {
  376. // Define $accessallowed
  377. if (($user->rights->$modulepart->lire) || ($user->rights->$modulepart->read) || ($user->rights->$modulepart->download)) $accessallowed=1; // No subpermission, we have checked on main permission
  378. elseif (preg_match('/^specimen/i',$original_file)) $accessallowed=1; // If link to a specimen
  379. elseif ($user->admin) $accessallowed=1; // If user is admin
  380. // For modules who wants to manage different levels of permissions for documents
  381. $subPermCategoryConstName = strtoupper($modulepart).'_SUBPERMCATEGORY_FOR_DOCUMENTS';
  382. if (! empty($conf->global->$subPermCategoryConstName))
  383. {
  384. $subPermCategory = $conf->global->$subPermCategoryConstName;
  385. if (! empty($subPermCategory) && (($user->rights->$modulepart->$subPermCategory->lire) || ($user->rights->$modulepart->$subPermCategory->read) || ($user->rights->$modulepart->$subPermCategory->download)))
  386. {
  387. $accessallowed=1;
  388. }
  389. }
  390. // Define $original_file
  391. $original_file=$conf->$modulepart->dir_output.'/'.$original_file;
  392. // Define $sqlprotectagainstexternals for modules who want to protect access using a SQL query.
  393. $sqlProtectConstName = strtoupper($modulepart).'_SQLPROTECTAGAINSTEXTERNALS_FOR_DOCUMENTS';
  394. if (! empty($conf->global->$sqlProtectConstName)) // If module want to define its own $sqlprotectagainstexternals
  395. {
  396. // Example: mymodule__SQLPROTECTAGAINSTEXTERNALS_FOR_DOCUMENTS = "SELECT fk_soc FROM ".MAIN_DB_PREFIX.$modulepart." WHERE ref='".$refname."' AND entity=".$conf->entity;
  397. eval('$sqlprotectagainstexternals = "'.$conf->global->$sqlProtectConstName.'";');
  398. }
  399. }
  400. }
  401. // Basic protection (against external users only)
  402. if ($user->societe_id > 0)
  403. {
  404. if ($sqlprotectagainstexternals)
  405. {
  406. $resql = $db->query($sqlprotectagainstexternals);
  407. if ($resql)
  408. {
  409. $num=$db->num_rows($resql);
  410. $i=0;
  411. while ($i < $num)
  412. {
  413. $obj = $db->fetch_object($resql);
  414. if ($user->societe_id != $obj->fk_soc)
  415. {
  416. $accessallowed=0;
  417. break;
  418. }
  419. $i++;
  420. }
  421. }
  422. }
  423. }
  424. // Security:
  425. // Limite acces si droits non corrects
  426. if (! $accessallowed)
  427. {
  428. accessforbidden();
  429. }
  430. // Security:
  431. // On interdit les remontees de repertoire ainsi que les pipe dans
  432. // les noms de fichiers.
  433. if (preg_match('/\.\./',$original_file) || preg_match('/[<>|]/',$original_file))
  434. {
  435. dol_syslog("Refused to deliver file ".$original_file);
  436. $file=basename($original_file); // Do no show plain path of original_file in shown error message
  437. dol_print_error(0,$langs->trans("ErrorFileNameInvalid",$file));
  438. exit;
  439. }
  440. if ($action == 'remove_file') // Remove a file
  441. {
  442. clearstatcache();
  443. dol_syslog("document.php remove $original_file $urlsource", LOG_DEBUG);
  444. // This test should be useless. We keep it to find bug more easily
  445. $original_file_osencoded=dol_osencode($original_file); // New file name encoded in OS encoding charset
  446. if (! file_exists($original_file_osencoded))
  447. {
  448. $file=basename($original_file); // Do no show plain path of original_file in shown error message
  449. dol_print_error(0,$langs->trans("ErrorFileDoesNotExists",$file));
  450. exit;
  451. }
  452. dol_delete_file($original_file);
  453. dol_syslog("document.php back to ".urldecode($urlsource), LOG_DEBUG);
  454. header("Location: ".urldecode($urlsource));
  455. return;
  456. }
  457. else // Open and return file
  458. {
  459. clearstatcache();
  460. $filename = basename($original_file);
  461. // Output file on browser
  462. dol_syslog("document.php download $original_file $filename content-type=$type");
  463. $original_file_osencoded=dol_osencode($original_file); // New file name encoded in OS encoding charset
  464. // This test if file exists should be useless. We keep it to find bug more easily
  465. if (! file_exists($original_file_osencoded))
  466. {
  467. dol_print_error(0,$langs->trans("ErrorFileDoesNotExists",$original_file));
  468. exit;
  469. }
  470. // Les drois sont ok et fichier trouve, on l'envoie
  471. if ($encoding) header('Content-Encoding: '.$encoding);
  472. if ($type) header('Content-Type: '.$type.(preg_match('/text/',$type)?'; charset="'.$conf->file->character_set_client:''));
  473. if ($attachment) header('Content-Disposition: attachment; filename="'.$filename.'"');
  474. else header('Content-Disposition: inline; filename="'.$filename.'"');
  475. // Ajout directives pour resoudre bug IE
  476. header('Cache-Control: Public, must-revalidate');
  477. header('Pragma: public');
  478. readfile($original_file_osencoded);
  479. }
  480. ?>