PageRenderTime 55ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/magmi/plugins/extra/general/remoteagent/magmi_remoteagent.php

https://gitlab.com/myurd/magmi-git
PHP | 498 lines | 424 code | 65 blank | 9 comment | 56 complexity | acb2a102203cf0c19c6938b85b22cd05 MD5 | raw file
  1. <?php
  2. // REMOTE AGENT IS A HTTP API ENABLING REMOTE FILE SAVING AND OTHER EXECUTION PROXYING
  3. // THIS IS USING A SINGLE BIG FILE ON PURPOSE , MAYBE LATER MORE COMPLEX STRUCTURE WILL BE USED
  4. class MRA_FSHelper
  5. {
  6. public static function isDirWritable($dir)
  7. {
  8. $test = @fopen("$dir/__testwr__", "w");
  9. if ($test == false) {
  10. return false;
  11. } else {
  12. fclose($test);
  13. unlink("$dir/__testwr__");
  14. }
  15. return true;
  16. }
  17. public static function getExecMode()
  18. {
  19. $is_disabled = array();
  20. $disabled = explode(',', ini_get('disable_functions'));
  21. foreach ($disabled as $disableFunction) {
  22. $is_disabled[] = trim($disableFunction);
  23. }
  24. foreach (array("popen", "shell_exec") as $func) {
  25. if (!in_array($func, $is_disabled)) {
  26. return $func;
  27. }
  28. }
  29. return null;
  30. }
  31. }
  32. class MRA_MagentoDirHandlerFactory
  33. {
  34. protected $_handlers = array();
  35. protected static $_instance;
  36. public function __construct()
  37. {
  38. }
  39. public static function getInstance()
  40. {
  41. if (!isset(self::$_instance)) {
  42. self::$_instance = new MagentoDirHandlerFactory();
  43. }
  44. return self::$_instance;
  45. }
  46. public function registerHandler($obj)
  47. {
  48. $cls = get_class($obj);
  49. if (!isset($this->_handlers[$cls])) {
  50. $this->_handlers[$cls] = $obj;
  51. }
  52. }
  53. public function getHandler($url)
  54. {
  55. foreach ($this->_handlers as $cls => $handler) {
  56. if ($handler->canHandle($url)) {
  57. return $handler;
  58. }
  59. }
  60. }
  61. }
  62. abstract class MRA_RemoteFileGetter
  63. {
  64. protected $_errors;
  65. abstract public function urlExists($url);
  66. abstract public function copyRemoteFile($url, $dest);
  67. public function getErrors()
  68. {
  69. return $this->_errors;
  70. }
  71. }
  72. class MRA_CURL_RemoteFileGetter extends RemoteFileGetter
  73. {
  74. protected $_curlh;
  75. public function createContext($url)
  76. {
  77. if ($this->_curlh == null) {
  78. $curl_url = str_replace(" ", "%20", $url);
  79. $context = curl_init($curl_url);
  80. $this->_curlh = $context;
  81. }
  82. return $this->_curlh;
  83. }
  84. public function destroyContext($url)
  85. {
  86. if ($this->_curlh != null) {
  87. curl_close($this->_curlh);
  88. $this->_curlh = null;
  89. }
  90. }
  91. public function urlExists($remoteurl)
  92. {
  93. $context = $this->createContext($remoteurl);
  94. // optimized lookup through curl
  95. /* head */
  96. curl_setopt($context, CURLOPT_HEADER, true);
  97. curl_setopt($context, CURLOPT_RETURNTRANSFER, true);
  98. curl_setopt($context, CURLOPT_CUSTOMREQUEST, 'HEAD');
  99. curl_setopt($context, CURLOPT_NOBODY, true);
  100. /* Get the HTML or whatever is linked in $url. */
  101. $response = curl_exec($context);
  102. /* Check for 404 (file not found). */
  103. $httpCode = curl_getinfo($context, CURLINFO_HTTP_CODE);
  104. $exists = ($httpCode == 200);
  105. /* retry on error */
  106. if ($httpCode == 503 or $httpCode == 403) {
  107. /* wait for a half second */
  108. usleep(500000);
  109. $response = curl_exec($context);
  110. $httpCode = curl_getinfo($context, CURLINFO_HTTP_CODE);
  111. $exists = ($httpCode == 200);
  112. }
  113. return $exists;
  114. }
  115. public function copyRemoteFile($url, $dest)
  116. {
  117. $this->_errors = array();
  118. $ret = true;
  119. $context = $this->createContext($url);
  120. if (!$this->urlExists($url)) {
  121. $this->_errors = array("type"=>"download error","message"=>"URL $url is unreachable");
  122. return false;
  123. }
  124. $fp = fopen($dest, "w");
  125. // add support for https urls
  126. curl_setopt($context, CURLOPT_SSL_VERIFYPEER, false);
  127. curl_setopt($context, CURLOPT_RETURNTRANSFER, false);
  128. curl_setopt($context, CURLOPT_CUSTOMREQUEST, 'GET');
  129. curl_setopt($context, CURLOPT_NOBODY, false);
  130. curl_setopt($context, CURLOPT_FILE, $fp);
  131. curl_setopt($context, CURLOPT_HEADER, 0);
  132. curl_setopt($context, CURLOPT_FAILONERROR, true);
  133. if (!ini_get('safe_mode')) {
  134. curl_setopt($context, CURLOPT_FOLLOWLOCATION, 1);
  135. }
  136. curl_exec($context);
  137. if (curl_getinfo($context, CURLINFO_HTTP_CODE) >= 400) {
  138. $this->_errors = array("type"=>"download error","message"=>curl_error($context));
  139. $ret = false;
  140. }
  141. fclose($fp);
  142. return $ret;
  143. }
  144. }
  145. class MRA_URLFopen_RemoteFileGetter extends RemoteFileGetter
  146. {
  147. public function urlExists($url)
  148. {
  149. $fname = $url;
  150. $h = @fopen($fname, "r");
  151. if ($h !== false) {
  152. $exists = true;
  153. fclose($h);
  154. }
  155. unset($h);
  156. }
  157. public function copyRemoteFile($url, $dest)
  158. {
  159. if (!$this->urlExists($url)) {
  160. $this->_errors = array("type"=>"target error","message"=>"URL $remoteurl is unreachable");
  161. return false;
  162. }
  163. $ok = @copy($url, $dest);
  164. if (!$ok) {
  165. $this->_errors = error_get_last();
  166. }
  167. return $ok;
  168. }
  169. }
  170. class MRA_RemoteFileGetterFactory
  171. {
  172. public static function getFGInstance()
  173. {
  174. $fginst = null;
  175. if (function_exists("curl_init")) {
  176. $fginst = new MRA_CURL_RemoteFileGetter();
  177. } else {
  178. $fginst = new MRA_URLFopen_RemoteFileGetter();
  179. }
  180. return $fginst;
  181. }
  182. }
  183. abstract class MRA_MagentoDirHandler
  184. {
  185. protected $_magdir;
  186. protected $_lasterror;
  187. protected $_exec_mode;
  188. public function __construct($magurl)
  189. {
  190. $this->_magdir = $magurl;
  191. $this->_lasterror = array();
  192. $this->_exec_mode = MRA_FSHelper::getExecMode();
  193. }
  194. abstract public function canhandle($url);
  195. abstract public function file_exists($filepath);
  196. abstract public function mkdir($path, $mask = null, $rec = false);
  197. abstract public function copy($srcpath, $destpath);
  198. abstract public function unlink($filepath);
  199. abstract public function chmod($filepath, $mask);
  200. abstract public function exec_cmd($cmd, $params);
  201. public function isExecEnabled()
  202. {
  203. return $this->_exec_mode != null;
  204. }
  205. }
  206. class MRA_LocalMagentoDirHandler extends MRA_MagentoDirHandler
  207. {
  208. public function __construct($magdir)
  209. {
  210. parent::__construct($magdir);
  211. MRA_MagentoDirHandlerFactory::getInstance()->registerHandler($this);
  212. }
  213. public function canHandle($url)
  214. {
  215. return (preg_match("|^.*?://.*$|", $url) == false);
  216. }
  217. public function file_exists($filename)
  218. {
  219. $mp = str_replace("//", "/", $this->_magdir . "/" . str_replace($this->_magdir, '', $filename));
  220. return file_exists($mp);
  221. }
  222. public function mkdir($path, $mask = null, $rec = false)
  223. {
  224. $mp = str_replace("//", "/", $this->_magdir . "/" . str_replace($this->_magdir, '', $path));
  225. if ($mask == null) {
  226. $mask = octdec('755');
  227. }
  228. $ok = @mkdir($mp, $mask, $rec);
  229. if (!$ok) {
  230. $this->_lasterror = error_get_last();
  231. }
  232. return $ok;
  233. }
  234. public function chmod($path, $mask)
  235. {
  236. $mp = str_replace("//", "/", $this->_magdir . "/" . str_replace($this->_magdir, '', $path));
  237. if ($mask == null) {
  238. $mask = octdec('755');
  239. }
  240. $ok = @chmod($mp, $mask);
  241. if (!$ok) {
  242. $this->_lasterror = error_get_last();
  243. }
  244. return $ok;
  245. }
  246. public function getLastError()
  247. {
  248. return $this->_lasterror;
  249. }
  250. public function unlink($path)
  251. {
  252. $mp = str_replace("//", "/", $this->_magdir . "/" . str_replace($this->_magdir, '', $path));
  253. return @unlink($mp);
  254. }
  255. public function copyFromRemote($remoteurl, $destpath)
  256. {
  257. $rfg = RemoteFileGetterFactory::getFGInstance();
  258. $mp = str_replace("//", "/", $this->_magdir . "/" . str_replace($this->_magdir, '', $destpath));
  259. $ok = $rfg->copyRemoteFile($remoteurl, $mp);
  260. if (!$ok) {
  261. $this->_lasterror = $rfg->getErrors();
  262. }
  263. unset($rfg);
  264. return $ok;
  265. }
  266. public function copy($srcpath, $destpath)
  267. {
  268. $result = false;
  269. if (preg_match('|^.*?://.*$|', $srcpath)) {
  270. $result = $this->copyFromRemote($srcpath, $destpath);
  271. } else {
  272. $result = @copy($srcpath, $destpath);
  273. if (!$result) {
  274. $this->_lasterror = error_get_last();
  275. }
  276. }
  277. return $result;
  278. }
  279. public function exec_cmd($cmd, $params)
  280. {
  281. $mp = str_replace("//", "/", $this->_magdir . "/" . str_replace($this->_magdir, '', $cmd));
  282. $full_cmd = $cmd . " " . $params;
  283. switch ($this->_exec_mode) {
  284. case "popen":
  285. $x = popen($full_cmd, "r");
  286. $out = "";
  287. while (!feof($x)) {
  288. $data = fread($x, 1024);
  289. $out .= $data;
  290. usleep(100000);
  291. }
  292. fclose($x);
  293. break;
  294. case "shell_exec":
  295. $out = @shell_exec($full_cmd);
  296. break;
  297. }
  298. if ($out === false || $out == null) {
  299. $this->_lasterror = error_get_last();
  300. return false;
  301. }
  302. return $out;
  303. }
  304. }
  305. class Magmi_RemoteAgent
  306. {
  307. private static $_instance;
  308. private $_mdh;
  309. private $_lasterror;
  310. public static $apidesc = array("getVersion"=>null,"copy"=>array("src","dest"),"mkdir"=>array("path","mask"),
  311. "chmod"=>array("path","mask"),"unlink"=>array("path"),"file_exists"=>array("path"),
  312. "exec_cmd"=>array("cmd","args"));
  313. public function __construct()
  314. {
  315. $this->_mdh = new MRA_LocalMagentoDirHandler(dirname(__FILE__));
  316. }
  317. public static function getStaticVersion()
  318. {
  319. return "1.0.2";
  320. }
  321. public function wrapResult($res)
  322. {
  323. if ($this->_lasterror == null) {
  324. return array("result"=>$res);
  325. } else {
  326. return array("error"=>$this->getLastError());
  327. }
  328. }
  329. public function getVersion()
  330. {
  331. return $this->wrapResult(array("version"=>self::getStaticVersion()));
  332. }
  333. public static function checkParams($params, $api)
  334. {
  335. $missing = array();
  336. $plist = Magmi_RemoteAgent::$apidesc[$api];
  337. for ($i = 0; $i < count($plist); $i++) {
  338. if (!isset($params[$plist[$i]])) {
  339. $missing[] = $plist[$i];
  340. }
  341. }
  342. return $missing;
  343. }
  344. public function getLastError()
  345. {
  346. $err = $this->_lasterror;
  347. $this->_lasterror = null;
  348. return $err;
  349. }
  350. public function copy($params)
  351. {
  352. $ok = $this->_mdh->copy($params['src'], $params['dest']);
  353. if (!$ok) {
  354. $this->_lasterror = $this->_mdh->getLastError();
  355. }
  356. return $this->wrapResult($ok);
  357. }
  358. public function file_exists($params)
  359. {
  360. $ok = $this->_mdh->file_exists($params['path']);
  361. return $this->wrapResult($ok);
  362. }
  363. public function mkdir($params)
  364. {
  365. $rec = isset($params['rec']);
  366. $ok = $this->_mdh->mkdir($params['path'], $params['mask'], $rec);
  367. if (!$ok) {
  368. $this->_lasterror = $this->_mdh->getLastError();
  369. }
  370. return $this->wrapResult($ok);
  371. }
  372. public function chmod($params)
  373. {
  374. $ok = $this->_mdh->chmod($params['path'], $params['mask']);
  375. if (!$ok) {
  376. $this->_lasterror = $this->_mdh->getLastError();
  377. }
  378. return $this->wrapResult($ok);
  379. }
  380. public function unlink($params)
  381. {
  382. $ok = $this->_mdh->unlink($params['path']);
  383. if (!$ok) {
  384. $this->_lasterror = $this->_mdh->getLastError();
  385. }
  386. return $this->wrapResult($ok);
  387. }
  388. public static function getInstance()
  389. {
  390. if (!isset(self::$_instance)) {
  391. self::$_instance = new Magmi_RemoteAgent();
  392. }
  393. return self::$_instance;
  394. }
  395. public function exec_cmd($params)
  396. {
  397. $out = $this->_mdh->exec_cmd($params['cmd'], $params['args']);
  398. if ($out === false) {
  399. $this->_lasterror = $this->_mdh->getLastError();
  400. }
  401. return $this->wrapResult($out);
  402. }
  403. }
  404. function sendResponse($calltype, $result)
  405. {
  406. header("Content-type: application/json");
  407. echo json_encode(array($calltype=>$result));
  408. }
  409. function buildError($errname, $errdata)
  410. {
  411. return array("error"=>array($errname,$errdata));
  412. }
  413. if (!class_exists('Magmi_Plugin')) {
  414. if (!isset($_REQUEST['api'])) {
  415. header('Status 406 : Unauthorized call', true, 406);
  416. exit();
  417. }
  418. $api = $_REQUEST['api'];
  419. if (!in_array($api, array_keys(Magmi_RemoteAgent::$apidesc))) {
  420. header('Status 406 : Unauthorized call', true, 406);
  421. exit();
  422. }
  423. $missing = Magmi_RemoteAgent::checkParams($_REQUEST, $api);
  424. if (count($missing) > 0) {
  425. header('Status 400 : Invalid parameters', true, 400);
  426. $error = buildError("missing mandatory parameters", implode(",", $missing));
  427. sendResponse($api, $error);
  428. } else {
  429. $mra = Magmi_RemoteAgent::getInstance();
  430. $result = $mra->$api($_REQUEST);
  431. sendResponse($api, $result);
  432. }
  433. }