api.class.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. <?php
  2. /* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
  3. * Copyright (C) 2016 Laurent Destailleur <eldy@users.sourceforge.net>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. use Luracast\Restler\Restler;
  19. use Luracast\Restler\RestException;
  20. use Luracast\Restler\Defaults;
  21. use Luracast\Restler\Format\UploadFormat;
  22. require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
  23. /**
  24. * Class for API REST v1
  25. */
  26. class DolibarrApi
  27. {
  28. /**
  29. * @var DoliDb $db Database object
  30. */
  31. static protected $db;
  32. /**
  33. * @var Restler $r Restler object
  34. */
  35. var $r;
  36. /**
  37. * Constructor
  38. *
  39. * @param DoliDb $db Database handler
  40. * @param string $cachedir Cache dir
  41. * @param boolean $refreshCache Update cache
  42. */
  43. function __construct($db, $cachedir='', $refreshCache=false)
  44. {
  45. global $conf, $dolibarr_main_url_root;
  46. if (empty($cachedir)) $cachedir = $conf->api->dir_temp;
  47. Defaults::$cacheDirectory = $cachedir;
  48. $this->db = $db;
  49. $production_mode = ( empty($conf->global->API_PRODUCTION_MODE) ? false : true );
  50. $this->r = new Restler($production_mode, $refreshCache);
  51. $urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($dolibarr_main_url_root));
  52. $urlwithroot=$urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
  53. $urlwithouturlrootautodetect=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim(DOL_MAIN_URL_ROOT));
  54. $urlwithrootautodetect=$urlwithouturlroot.DOL_URL_ROOT; // This is to use local domain autodetected by dolibarr from url
  55. $this->r->setBaseUrls($urlwithouturlroot, $urlwithouturlrootautodetect);
  56. $this->r->setAPIVersion(1);
  57. //$this->r->setSupportedFormats('json');
  58. //$this->r->setSupportedFormats('jsonFormat');
  59. }
  60. /**
  61. * Executed method when API is called without parameter
  62. *
  63. * Display a short message an return a http code 200
  64. *
  65. * @return array
  66. */
  67. /* Disabled, most APIs does not share same signature for method index
  68. function index()
  69. {
  70. return array(
  71. 'success' => array(
  72. 'code' => 200,
  73. 'message' => __class__.' is up and running!'
  74. )
  75. );
  76. }*/
  77. /**
  78. * Clean sensible object datas
  79. *
  80. * @param object $object Object to clean
  81. * @return array Array of cleaned object properties
  82. */
  83. function _cleanObjectDatas($object) {
  84. // Remove $db object property for object
  85. unset($object->db);
  86. unset($object->ismultientitymanaged);
  87. unset($object->restrictiononfksoc);
  88. // Remove linkedObjects. We should already have linkedObjectIds that avoid huge responses
  89. unset($object->linkedObjects);
  90. unset($object->lignes); // we don't want lignes, we want only ->lines
  91. unset($object->fields);
  92. unset($object->oldline);
  93. unset($object->error);
  94. unset($object->errors);
  95. unset($object->ref_previous);
  96. unset($object->ref_next);
  97. unset($object->ref_int);
  98. unset($object->projet); // Should be fk_project
  99. unset($object->project); // Should be fk_project
  100. unset($object->author); // Should be fk_user_author
  101. unset($object->timespent_old_duration);
  102. unset($object->timespent_id);
  103. unset($object->timespent_duration);
  104. unset($object->timespent_date);
  105. unset($object->timespent_datehour);
  106. unset($object->timespent_withhour);
  107. unset($object->timespent_fk_user);
  108. unset($object->timespent_note);
  109. unset($object->statuts);
  110. unset($object->statuts_short);
  111. unset($object->statuts_logo);
  112. unset($object->statuts_long);
  113. unset($object->labelstatut);
  114. unset($object->labelstatut_short);
  115. unset($object->element);
  116. unset($object->fk_element);
  117. unset($object->table_element);
  118. unset($object->table_element_line);
  119. unset($object->class_element_line);
  120. unset($object->picto);
  121. unset($object->facturee); // Replace with billed
  122. unset($object->fieldsforcombobox);
  123. unset($object->comments);
  124. unset($object->skip_update_total);
  125. unset($object->context);
  126. // Remove the $oldcopy property because it is not supported by the JSON
  127. // encoder. The following error is generated when trying to serialize
  128. // it: "Error encoding/decoding JSON: Type is not supported"
  129. // Note: Event if this property was correctly handled by the JSON
  130. // encoder, it should be ignored because keeping it would let the API
  131. // have a very strange behavior: calling PUT and then GET on the same
  132. // resource would give different results:
  133. // PUT /objects/{id} -> returns object with oldcopy = previous version of the object
  134. // GET /objects/{id} -> returns object with oldcopy empty
  135. unset($object->oldcopy);
  136. // If object has lines, remove $db property
  137. if (isset($object->lines) && is_array($object->lines) && count($object->lines) > 0) {
  138. $nboflines = count($object->lines);
  139. for ($i=0; $i < $nboflines; $i++)
  140. {
  141. $this->_cleanObjectDatas($object->lines[$i]);
  142. unset($object->lines[$i]->contact);
  143. unset($object->lines[$i]->contact_id);
  144. unset($object->lines[$i]->country);
  145. unset($object->lines[$i]->country_id);
  146. unset($object->lines[$i]->country_code);
  147. unset($object->lines[$i]->mode_reglement_id);
  148. unset($object->lines[$i]->mode_reglement_code);
  149. unset($object->lines[$i]->mode_reglement);
  150. unset($object->lines[$i]->cond_reglement_id);
  151. unset($object->lines[$i]->cond_reglement_code);
  152. unset($object->lines[$i]->cond_reglement);
  153. unset($object->lines[$i]->fk_delivery_address);
  154. unset($object->lines[$i]->fk_projet);
  155. unset($object->lines[$i]->thirdparty);
  156. unset($object->lines[$i]->user);
  157. unset($object->lines[$i]->model_pdf);
  158. unset($object->lines[$i]->modelpdf);
  159. unset($object->lines[$i]->note_public);
  160. unset($object->lines[$i]->note_private);
  161. unset($object->lines[$i]->fk_incoterms);
  162. unset($object->lines[$i]->libelle_incoterms);
  163. unset($object->lines[$i]->location_incoterms);
  164. unset($object->lines[$i]->name);
  165. unset($object->lines[$i]->lastname);
  166. unset($object->lines[$i]->firstname);
  167. unset($object->lines[$i]->civility_id);
  168. unset($object->lines[$i]->fk_multicurrency);
  169. unset($object->lines[$i]->multicurrency_code);
  170. unset($object->lines[$i]->shipping_method_id);
  171. }
  172. }
  173. if (! empty($object->thirdparty) && is_object($object->thirdparty))
  174. {
  175. $this->_cleanObjectDatas($object->thirdparty);
  176. }
  177. return $object;
  178. }
  179. /**
  180. * Check user access to a resource
  181. *
  182. * Check access by user to a given resource
  183. *
  184. * @param string $resource element to check
  185. * @param int $resource_id Object ID if we want to check a particular record (optional) is linked to a owned thirdparty (optional).
  186. * @param type $dbtablename 'TableName&SharedElement' with Tablename is table where object is stored. SharedElement is an optional key to define where to check entity. Not used if objectid is null (optional)
  187. * @param string $feature2 Feature to check, second level of permission (optional). Can be or check with 'level1|level2'.
  188. * @param string $dbt_keyfield Field name for socid foreign key if not fk_soc. Not used if objectid is null (optional)
  189. * @param string $dbt_select Field name for select if not rowid. Not used if objectid is null (optional)
  190. * @throws RestException
  191. */
  192. static function _checkAccessToResource($resource, $resource_id=0, $dbtablename='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid') {
  193. // Features/modules to check
  194. $featuresarray = array($resource);
  195. if (preg_match('/&/', $resource)) {
  196. $featuresarray = explode("&", $resource);
  197. }
  198. else if (preg_match('/\|/', $resource)) {
  199. $featuresarray = explode("|", $resource);
  200. }
  201. // More subfeatures to check
  202. if (! empty($feature2)) {
  203. $feature2 = explode("|", $feature2);
  204. }
  205. return checkUserAccessToObject(DolibarrApiAccess::$user, $featuresarray, $resource_id, $dbtablename, $feature2, $dbt_keyfield, $dbt_select);
  206. }
  207. /**
  208. * Return if a $sqlfilters parameter is valid
  209. *
  210. * @param string $sqlfilters sqlfilter string
  211. * @return boolean True if valid, False if not valid
  212. */
  213. function _checkFilters($sqlfilters)
  214. {
  215. //$regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)';
  216. //$tmp=preg_replace_all('/'.$regexstring.'/', '', $sqlfilters);
  217. $tmp=$sqlfilters;
  218. $ok=0;
  219. $i=0; $nb=strlen($tmp);
  220. $counter=0;
  221. while ($i < $nb)
  222. {
  223. if ($tmp[$i]=='(') $counter++;
  224. if ($tmp[$i]==')') $counter--;
  225. if ($counter < 0)
  226. {
  227. $error="Bad sqlfilters=".$sqlfilters;
  228. dol_syslog($error, LOG_WARNING);
  229. return false;
  230. }
  231. $i++;
  232. }
  233. return true;
  234. }
  235. /**
  236. * Function to forge a SQL criteria
  237. *
  238. * @param array $matches Array of found string by regex search
  239. * @return string Forged criteria. Example: "t.field like 'abc%'"
  240. */
  241. static function _forge_criteria_callback($matches)
  242. {
  243. global $db;
  244. //dol_syslog("Convert matches ".$matches[1]);
  245. if (empty($matches[1])) return '';
  246. $tmp=explode(':',$matches[1]);
  247. if (count($tmp) < 3) return '';
  248. $tmpescaped=$tmp[2];
  249. if (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis))
  250. {
  251. $tmpescaped = "'".$db->escape($regbis[1])."'";
  252. }
  253. else
  254. {
  255. $tmpescaped = $db->escape($tmpescaped);
  256. }
  257. return $db->escape($tmp[0]).' '.strtoupper($db->escape($tmp[1]))." ".$tmpescaped;
  258. }
  259. }