PageRenderTime 71ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/libs/PluginManagement.php

https://gitlab.com/fork/hotarucms
PHP | 1276 lines | 738 code | 248 blank | 290 comment | 165 complexity | 3a80c10934d1a02c14fc9d2ac1df4f55 MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /**
  3. * Plugin Management Functions
  4. *
  5. * PHP version 5
  6. *
  7. * LICENSE: Hotaru CMS is free software: you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation, either version 3 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * Hotaru CMS is distributed in the hope that it will be useful, but WITHOUT
  13. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. * FITNESS FOR A PARTICULAR PURPOSE.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with Hotaru CMS. If not, see http://www.gnu.org/licenses/.
  18. *
  19. * @category Content Management System
  20. * @package HotaruCMS
  21. * @author Hotaru CMS Team
  22. * @copyright Copyright (c) 2009 - 2013, Hotaru CMS
  23. * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
  24. * @link http://www.hotarucms.org/
  25. */
  26. class PluginManagement
  27. {
  28. /**
  29. * Get an array of plugins
  30. *
  31. * Reads plugin info directly from top of plugin files, then compares each
  32. * plugin to the database. If present and latest version, reads info from
  33. * the database. If not in database or newer version, uses info from plugin
  34. * file. Used by Plugin Management.
  35. *
  36. * @return array $allplugins
  37. */
  38. public function getPlugins($h)
  39. {
  40. $plugins_array = $this->getPluginsMeta();
  41. $count = 0;
  42. $allplugins = array();
  43. if ($plugins_array) {
  44. foreach ($plugins_array as $plugin_details) {
  45. $allplugins[$count] = array();
  46. if ($h->allPluginDetails) {
  47. // get details from memory if we have them..
  48. $plugin_row = $h->readPlugin($plugin_details['folder']);
  49. } else {
  50. $sql = "SELECT * FROM " . TABLE_PLUGINS . " WHERE plugin_folder = %s";
  51. if (!MEEKRODB) {
  52. $plugin_row = $h->db->get_row($h->db->prepare($sql, $plugin_details['folder']));
  53. } else {
  54. $plugin_row = $h->mdb->queryFirstRow($sql, $plugin_details['folder']);
  55. //$plugin_row = models___Plugins::first(array('conditions'=>array('plugin_folder = ?', $plugin_details['folder'])));
  56. }
  57. }
  58. if ($plugin_row)
  59. {
  60. // if plugin is in the database...
  61. $allplugins[$count]['id'] = $plugin_row->plugin_id; // need this for when we reorder the lists - use id in the sort_id col
  62. $allplugins[$count]['name'] = $plugin_row->plugin_name;
  63. $allplugins[$count]['description'] = $plugin_row->plugin_desc;
  64. $allplugins[$count]['folder'] = $plugin_row->plugin_folder;
  65. $allplugins[$count]['author'] = $plugin_row->plugin_author;
  66. $allplugins[$count]['authorurl'] = urldecode($plugin_row->plugin_authorurl);
  67. if ($plugin_row->plugin_enabled) {
  68. $allplugins[$count]['status'] = 'active';
  69. } else {
  70. $allplugins[$count]['status'] = 'inactive';
  71. }
  72. $allplugins[$count]['version'] = $plugin_row->plugin_version;
  73. $allplugins[$count]['latestversion'] = $plugin_row->plugin_latestversion;
  74. $allplugins[$count]['install'] = "installed";
  75. $allplugins[$count]['location'] = "database";
  76. $allplugins[$count]['settings'] = $h->hasSettings($allplugins[$count]['folder']); // true or false
  77. $allplugins[$count]['order'] = $plugin_row->plugin_order;
  78. }
  79. else
  80. {
  81. // if plugin is not in database...
  82. $allplugins[$count]['name'] = $plugin_details['name'];
  83. $allplugins[$count]['description'] = $plugin_details['description'];
  84. $allplugins[$count]['folder'] = $plugin_details['folder'];
  85. if (isset($plugin_details['author'])) {
  86. $allplugins[$count]['author'] = $plugin_details['author'];
  87. }
  88. if (isset($plugin_details['authorurl'])) {
  89. $allplugins[$count]['authorurl'] = urldecode($plugin_details['authorurl']);
  90. }
  91. $allplugins[$count]['status'] = "inactive";
  92. $allplugins[$count]['version'] = $plugin_details['version'];
  93. $allplugins[$count]['install'] = "install";
  94. $allplugins[$count]['location'] = "folder";
  95. $allplugins[$count]['order'] = 0;
  96. }
  97. // Conditions for "active"...
  98. if ($allplugins[$count]['status'] == 'active') {
  99. $allplugins[$count]['active'] = "<div class='switch switch-small' id='switch#". $allplugins[$count]['folder'] . "'><input type=\"checkbox\" checked=\"checked\"></div> </a>";
  100. } else {
  101. $allplugins[$count]['active'] = "<div class='switch switch-small' id='switch#". $allplugins[$count]['folder'] . "'><input type=\"checkbox\"></div>";
  102. }
  103. // Conditions for "install"...
  104. if ($allplugins[$count]['install'] == 'install') {
  105. $allplugins[$count]['install'] = "<a href='" . SITEURL . "admin_index.php?page=plugin_management&amp;action=install&amp;plugin=". $allplugins[$count]['folder'] . "'><i class=\"icon-download-alt\"></i> </a>";
  106. } else {
  107. $allplugins[$count]['install'] = "<a href='" . SITEURL . "admin_index.php?page=plugin_management&amp;action=uninstall&amp;plugin=". $allplugins[$count]['folder'] . "'><i class=\"icon-trash\"></i> </a>";
  108. }
  109. // Conditions for "requires"...
  110. if (isset($plugin_details['requires']) && $plugin_details['requires']) {
  111. $h->plugin->requires = $plugin_details['requires'];
  112. $this->requiresToDependencies($h);
  113. // Converts plugin folder names to well formatted names...
  114. foreach ($h->plugin->dependencies as $this_plugin => $version)
  115. {
  116. $h->plugin->dependencies[$this_plugin] = $version;
  117. $allplugins[$count]['requires'][$this_plugin] = $h->plugin->dependencies[$this_plugin];
  118. }
  119. } else {
  120. $allplugins[$count]['requires'] = array();
  121. }
  122. // Conditions for "order"...
  123. // The order is sorted numerically in the plugin_management.php template, so we need separate order and order_output elements.
  124. if ($allplugins[$count]['order'] != 0) {
  125. $order = $allplugins[$count]['order'];
  126. $allplugins[$count]['order_output'] = "<a href='" . SITEURL;
  127. $allplugins[$count]['order_output'] .= "admin_index.php?page=plugin_management&amp;";
  128. $allplugins[$count]['order_output'] .= "action=orderup&amp;plugin=". $allplugins[$count]['folder'];
  129. $allplugins[$count]['order_output'] .= "&amp;order=" . $order . "'>";
  130. $allplugins[$count]['order_output'] .= "<i class=\"icon-chevron-up\"></i> ";
  131. $allplugins[$count]['order_output'] .= "</a> \n&nbsp;<a href='" . SITEURL;
  132. $allplugins[$count]['order_output'] .= "admin_index.php?page=plugin_management&amp;";
  133. $allplugins[$count]['order_output'] .= "action=orderdown&amp;plugin=". $allplugins[$count]['folder'];
  134. $allplugins[$count]['order_output'] .= "&amp;order=" . $order . "'>";
  135. $allplugins[$count]['order_output'] .= "<i class=\"icon-chevron-down\"></i> ";
  136. $allplugins[$count]['order_output'] .= "</a>\n";
  137. } else {
  138. $allplugins[$count]['order_output'] = "";
  139. }
  140. $count++;
  141. }
  142. }
  143. return $allplugins;
  144. }
  145. /**
  146. * Used by array_filter to keep only installed plugins
  147. */
  148. public function getInstalledPlugins($var)
  149. {
  150. if ($var['location'] == 'database') { return $var; }
  151. }
  152. /**
  153. * Used by array_filter in template to keep only installed plugins
  154. */
  155. public function getUninstalledPlugins($var)
  156. {
  157. if ($var['location'] == 'folder') { return $var; }
  158. }
  159. /**
  160. * Read and return plugin info directly from plugin files.
  161. */
  162. public function getPluginsMeta()
  163. {
  164. $plugin_list = getFilenames(PLUGINS, "short");
  165. $plugins_array = array();
  166. foreach ($plugin_list as $plugin_folder_name)
  167. {
  168. if($plugin_metadata = $this->readPluginMeta($plugin_folder_name)) {
  169. array_push($plugins_array, $plugin_metadata);
  170. }
  171. }
  172. return $plugins_array; // return plugins in alphabetical order
  173. }
  174. /**
  175. * Read and return plugin info from top of a plugin file.
  176. *
  177. * @param string $plugin_file - a file from the /plugins folder
  178. * @return array|false
  179. */
  180. public function readPluginMeta($plugin_file)
  181. {
  182. if ($plugin_file === 'placeholder.txt' || $plugin_file === 'README.md') { return false; }
  183. // Include the generic_pmd class that reads post metadata from the a plugin
  184. require_once(EXTENSIONS . 'GenericPHPConfig/class.metadata.php');
  185. $metaReader = new generic_pmd();
  186. $plugin_metadata = $metaReader->read(PLUGINS . $plugin_file . "/" . $plugin_file . ".php");
  187. if ($plugin_metadata) { return $plugin_metadata; } else { return false; }
  188. }
  189. /**
  190. * Converts $h->plugin->requires into $h->plugin->dependencies array.
  191. * Result is an array containing 'plugin' -> 'version' pairs
  192. */
  193. public function requiresToDependencies($h)
  194. {
  195. // unset each key from previous time here
  196. foreach ($h->plugin->dependencies as $k => $v) {
  197. unset($h->plugin->dependencies[$k]);
  198. }
  199. foreach (explode(',', $h->plugin->requires) as $pair)
  200. {
  201. $pair_array = explode(' ', trim(strtolower($pair)));
  202. $pair_array ? $k = $pair_array[0] : $k=$h->lang("admin_plugins_install_unknown_plugin");
  203. count($pair_array) > 1 ? $v = $pair_array[1] : $v=0;
  204. $h->plugin->dependencies[$k] = $v;
  205. }
  206. }
  207. /**
  208. * Add a plugin to the plugins table
  209. *
  210. * @param int $upgrade flag to indicate we need to show "Upgraded!" instead of "Installed!" message
  211. */
  212. public function install($h, $upgrade = 0)
  213. {
  214. // Clear the database cache to ensure stored plugins and hooks
  215. // are up-to-date.
  216. $h->deleteFiles(CACHE . 'db_cache');
  217. // Clear the css/js cache to ensure any new ones get included
  218. $h->deleteFiles(CACHE . 'css_js_cache');
  219. // Clear the language cache to ensure any new language files get included
  220. $h->clearCache('lang_cache', false);
  221. $h->messages['db, css, language caches cleared'] = 'alert-info';
  222. // Read meta from the top of the plugin file
  223. $plugin_metadata = $this->readPluginMeta($h->plugin->folder);
  224. $h->plugin->enabled = 1; // Enable it when we add it to the database.
  225. $this->assignPluginMeta($h, $plugin_metadata);
  226. $dependency_error = 0;
  227. foreach ($h->plugin->dependencies as $dependency => $version)
  228. {
  229. if (version_compare($version, $h->getPluginVersion($dependency), '>')) {
  230. $dependency_error = 1;
  231. }
  232. }
  233. if ($dependency_error == 1)
  234. {
  235. foreach ($h->plugin->dependencies as $dependency => $version)
  236. {
  237. if (($h->isActive($dependency) == 'inactive')
  238. || version_compare($version, $h->getPluginVersion($dependency), '>')) {
  239. $dependency = make_name($dependency);
  240. $h->messages[$h->lang("admin_plugins_install_sorry") . " " . $h->plugin->name . " " . $h->lang("admin_plugins_install_requires") . " " . $dependency . " " . $version] = 'red';
  241. }
  242. }
  243. return false;
  244. }
  245. // set a new plugin order if NOT upgrading
  246. if ($upgrade == 0) {
  247. $sql = "REPLACE INTO " . TABLE_PLUGINS . " (plugin_enabled, plugin_name, plugin_folder, plugin_class, plugin_extends, plugin_type, plugin_desc, plugin_requires, plugin_version, plugin_author, plugin_authorurl, plugin_updateby) VALUES (%d, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %d)";
  248. $h->db->query($h->db->prepare($sql, $h->plugin->enabled, $h->plugin->name, $h->plugin->folder, $h->plugin->class, $h->plugin->extends, $h->plugin->type, $h->plugin->desc, $h->plugin->requires, $h->plugin->version, $h->plugin->author, urlencode($h->plugin->authorurl), $h->currentUser->id));
  249. // Get the last order number - doing this after REPLACE INTO because
  250. // we don't know whether the above will insert or replace.
  251. $sql = "SELECT plugin_order FROM " . TABLE_PLUGINS . " ORDER BY plugin_order DESC LIMIT 1";
  252. $highest_order = $h->db->get_var($h->db->prepare($sql));
  253. // Give the new plugin the order number + 1
  254. $sql = "UPDATE " . TABLE_PLUGINS . " SET plugin_order = %d WHERE plugin_id = LAST_INSERT_ID()";
  255. $h->db->query($h->db->prepare($sql, ($highest_order + 1)));
  256. } else {
  257. // upgrading:
  258. $sql = "UPDATE " . TABLE_PLUGINS . " SET plugin_enabled = %d, plugin_name = %s, plugin_folder = %s, plugin_class = %s, plugin_extends = %s, plugin_type = %s, plugin_desc = %s, plugin_requires = %s, plugin_version = %s, plugin_author = %s, plugin_authorurl = %s, plugin_updateby = %d WHERE plugin_folder = %s";
  259. $h->db->query($h->db->prepare($sql, $h->plugin->enabled, $h->plugin->name, $h->plugin->folder, $h->plugin->class, $h->plugin->extends, $h->plugin->type, $h->plugin->desc, $h->plugin->requires, $h->plugin->version, $h->plugin->author, urlencode($h->plugin->authorurl), $h->currentUser->id, $h->plugin->folder));
  260. }
  261. // Add any plugin hooks to the hooks table
  262. $this->addPluginHooks($h);
  263. // Force inclusion of a language file (if exists) because the
  264. // plugin isn't ready to include it itself yet.
  265. $h->includeLanguage();
  266. $result = $h->pluginHook('install_plugin', $h->plugin->folder);
  267. // Re-sort all orders and remove any accidental gaps
  268. $this->refreshPluginOrder($h);
  269. $this->sortPluginHooks($h);
  270. // For plugins to avoid showing this success message, they need to
  271. // return a non-boolean value to $result.
  272. if (!is_array($result))
  273. {
  274. if ($upgrade == 0) {
  275. $h->messages[$h->lang("admin_plugins_install_done")] = 'green';
  276. } else {
  277. $h->messages[$h->lang("admin_plugins_upgrade_done")] = 'green';
  278. }
  279. }
  280. }
  281. /**
  282. * Assign info from top of a plugin file to the current object.
  283. *
  284. * @param array $plugin_metadata
  285. * @return array|false
  286. */
  287. public function assignPluginMeta($h, $plugin_metadata)
  288. {
  289. if (!$plugin_metadata) { return false; }
  290. $h->plugin->name = $plugin_metadata['name'];
  291. $h->plugin->desc = $plugin_metadata['description'];
  292. $h->plugin->version = $plugin_metadata['version'];
  293. $h->plugin->folder = $plugin_metadata['folder'];
  294. $h->plugin->class = $plugin_metadata['class'];
  295. if (!isset($plugin_metadata['hooks'])) {
  296. $h->plugin->hooks = array();
  297. } else {
  298. $h->plugin->hooks = explode(',', $plugin_metadata['hooks']);
  299. }
  300. if (isset($plugin_metadata['extends'])) { $h->plugin->extends = $plugin_metadata['extends']; }
  301. if (isset($plugin_metadata['type'])) { $h->plugin->type = $plugin_metadata['type']; }
  302. if (isset($plugin_metadata['author'])) { $h->plugin->author = $plugin_metadata['author']; }
  303. if (isset($plugin_metadata['authorurl'])) { $h->plugin->authorurl = $plugin_metadata['authorurl']; }
  304. if (isset($plugin_metadata['requires']) && $plugin_metadata['requires']) {
  305. $h->plugin->requires = $plugin_metadata['requires'];
  306. $this->requiresToDependencies($h);
  307. }
  308. return true;
  309. }
  310. /**
  311. * Adds all hooks for a given plugin
  312. */
  313. public function addPluginHooks($h)
  314. {
  315. $values = '';
  316. $pvalues = array();
  317. $pvalues[0] = "temp"; // will be filled with $sql
  318. foreach ($h->plugin->hooks as $hook)
  319. {
  320. $exists = $this->isHook($h, trim($hook));
  321. if (!$exists) {
  322. $values .= "(%s, %s, %d), ";
  323. array_push($pvalues, $h->plugin->folder);
  324. array_push($pvalues, trim($hook));
  325. array_push($pvalues, $h->currentUser->id);
  326. }
  327. }
  328. if ($values) {
  329. $values = rstrtrim($values, ", "); // strip off trailing comma
  330. $pvalues[0] = "INSERT INTO " . TABLE_PLUGINHOOKS . " (plugin_folder, plugin_hook, plugin_updateby) VALUES " . $values;
  331. $h->db->query($h->db->prepare($pvalues));
  332. }
  333. }
  334. /**
  335. * Check if a plugin hook exists for a given plugin
  336. *
  337. * @param string $folder plugin folder name
  338. * @param string $hook plugin hook name
  339. * @return int|false
  340. */
  341. public function isHook($h, $hook = "", $folder = "")
  342. {
  343. if (!$folder) { $folder = $h->plugin->folder; }
  344. $sql = "SELECT count(phook_id) FROM " . TABLE_PLUGINHOOKS . " WHERE plugin_folder = %s AND plugin_hook = %s";
  345. if ($h->db->get_var($h->db->prepare($sql, $folder, $hook))) { return true;} else { return false; }
  346. }
  347. /**
  348. * Uninstall all plugins
  349. */
  350. public function uninstallAll($h)
  351. {
  352. // Clear the database cache to ensure plugins and hooks are up-to-date.
  353. $h->deleteFiles(CACHE . 'db_cache');
  354. // Clear the css/js cache to ensure any new ones get included
  355. $h->deleteFiles(CACHE . 'css_js_cache');
  356. // Clear the language cache to ensure any new language files get included
  357. $h->clearCache('lang_cache', false);
  358. $h->messages['db, css, language caches cleared'] = 'alert-info';
  359. $h->db->query("TRUNCATE TABLE " . TABLE_PLUGINS);
  360. $h->db->query("TRUNCATE TABLE " . TABLE_PLUGINHOOKS);
  361. $h->messages[$h->lang("admin_plugins_uninstall_all_done")] = 'green';
  362. }
  363. /**
  364. * Delete plugin from table_plugins, pluginhooks and pluginsettings
  365. *
  366. * @param int $upgrade flag to disable message
  367. */
  368. public function uninstall($h, $upgrade = 0)
  369. {
  370. // Clear the database cache to ensure plugins and hooks are up-to-date.
  371. $h->deleteFiles(CACHE . 'db_cache');
  372. // Clear the css/js cache to ensure this plugin's files are removed
  373. $h->deleteFiles(CACHE . 'css_js_cache');
  374. // Clear the language cache to ensure any new language files get included
  375. $h->clearCache('lang_cache', false);
  376. $h->messages['db, css, language caches cleared'] = 'alert-info';
  377. if ($upgrade == 0) { // don't delete plugin when we're upgrading
  378. $h->db->query($h->db->prepare("DELETE FROM " . TABLE_PLUGINS . " WHERE plugin_folder = %s", $h->plugin->folder));
  379. }
  380. $h->db->query($h->db->prepare("DELETE FROM " . TABLE_PLUGINHOOKS . " WHERE plugin_folder = %s", $h->plugin->folder));
  381. // Settings aren't deleted anymore, but a user can do so manually from Admin->Maintenance
  382. //$h->db->query($h->db->prepare("DELETE FROM " . TABLE_PLUGINSETTINGS . " WHERE plugin_folder = %s", $h->plugin->folder));
  383. $h->pluginHook('uninstall_plugin', $h->plugin->folder);
  384. if ($upgrade == 0) {
  385. $h->messages[$h->lang("admin_plugins_uninstall_done")] = 'green';
  386. }
  387. // Re-sort all orders and remove any accidental gaps
  388. $this->refreshPluginOrder($h);
  389. $this->sortPluginHooks($h);
  390. }
  391. /**
  392. * Removes gaps in plugin order where plugins have been uninstalled.
  393. */
  394. public function refreshPluginOrder($h)
  395. {
  396. $need_refresh = false;
  397. // First, do a quick query and simple loop to check for gaps
  398. $sql = "SELECT plugin_order FROM " . TABLE_PLUGINS . " ORDER BY plugin_order ASC";
  399. $rows = $h->db->get_results($h->db->prepare($sql));
  400. if ($rows) {
  401. $previous_row = 0;
  402. foreach ($rows as $row)
  403. {
  404. if ($row->plugin_order != ($previous_row + 1)) {
  405. $need_refresh = true;
  406. break;
  407. } else {
  408. $previous_row = $row->plugin_order; // increment $previous_row
  409. }
  410. }
  411. }
  412. if (!$need_refresh) { return true; }
  413. // Gaps found! Refresh all the plugin orders to fill the gaps!
  414. $sql = "SELECT * FROM " . TABLE_PLUGINS . " ORDER BY plugin_order ASC";
  415. $rows = $h->db->get_results($h->db->prepare($sql));
  416. if ($rows) {
  417. $i = 1;
  418. foreach ($rows as $row)
  419. {
  420. $sql = "UPDATE " . TABLE_PLUGINS . " SET plugin_order = %d WHERE plugin_id = %d";
  421. $h->db->query($h->db->prepare($sql, $i, $row->plugin_id));
  422. $i++;
  423. }
  424. }
  425. // optimize the table
  426. $h->db->query("OPTIMIZE TABLE " . TABLE_PLUGINS);
  427. return true;
  428. }
  429. /**
  430. * Orders the plugin hooks by plugin_order
  431. */
  432. public function sortPluginHooks($h)
  433. {
  434. $sql = "SELECT p.plugin_folder, p.plugin_order, p.plugin_id, h.* FROM " . TABLE_PLUGINHOOKS . " h, " . TABLE_PLUGINS . " p WHERE p.plugin_folder = h.plugin_folder ORDER BY p.plugin_order ASC";
  435. $rows = $h->db->get_results($h->db->prepare($sql));
  436. // Remove all hooks for this site
  437. $h->db->query($h->db->prepare("TRUNCATE TABLE " . TABLE_PLUGINHOOKS));
  438. $values = '';
  439. $pvalues = array();
  440. $pvalues[0] = "temp"; // will be filled with $sql
  441. // Add plugin hooks back into the hooks table
  442. if ($rows) {
  443. foreach ($rows as $row)
  444. {
  445. $values .= "(%s, %s, %d), ";
  446. array_push($pvalues, $row->plugin_folder);
  447. array_push($pvalues, $row->plugin_hook);
  448. array_push($pvalues, $h->currentUser->id);
  449. }
  450. $values = rstrtrim($values, ", "); // strip off trailing comma
  451. $pvalues[0] = "INSERT INTO " . TABLE_PLUGINHOOKS . " (plugin_folder, plugin_hook, plugin_updateby) VALUES " . $values;
  452. $h->db->query($h->db->prepare($pvalues));
  453. }
  454. }
  455. /**
  456. * Upgrade plugin
  457. *
  458. * @param string $folder plugin folder name
  459. *
  460. * Note: This function does nothing by itself other than read the latest
  461. * file's metadata.
  462. */
  463. public function upgrade($h)
  464. {
  465. // Read meta from the top of the plugin file
  466. $plugin_metadata = $this->readPluginMeta($h->plugin->folder);
  467. $h->plugin->enabled = 1; // Enable it when we add it to the database.
  468. $this->assignPluginMeta($h, $plugin_metadata);
  469. $this->uninstall($h, 1); // 1 indicates that "upgrade" is true, used to disable the "Uninstalled" message
  470. $this->install($h, 1); // 1 indicates that "upgrade" is true.
  471. }
  472. /**
  473. * Enables or disables a plugin, installing if necessary
  474. *
  475. * @param int $enabled
  476. * Note: This function does not uninstall/delete a plugin.
  477. */
  478. public function activateDeactivate($h, $enabled = 0, $ajax = false)
  479. { // 0 = deactivate, 1 = activate
  480. // Clear the database cache to ensure plugins and hooks are up-to-date.
  481. $h->deleteFiles(CACHE . 'db_cache');
  482. // Clear the css/js cache to ensure any new ones get included
  483. $h->deleteFiles(CACHE . 'css_js_cache');
  484. $h->messages['db, css caches cleared'] = 'alert-info';
  485. // Get the enabled status for this plugin...
  486. $plugin_row = $h->db->get_row($h->db->prepare("SELECT plugin_folder, plugin_enabled FROM " . TABLE_PLUGINS . " WHERE plugin_folder = %s", $h->plugin->folder));
  487. // If no result, then it's obviously not installed...
  488. if (!$plugin_row)
  489. {
  490. // If the user is activating the plugin, go and install it...
  491. if ($enabled == 1) { $this->install($h); }
  492. }
  493. else
  494. {
  495. $result = $this->activateDeactivateDo($h, $plugin_row, $enabled);
  496. return $result;
  497. }
  498. }
  499. /**
  500. * Enables or disables all plugins, installing if necessary
  501. *
  502. * @param int $enabled
  503. * Note: This function does not uninstall/delete a plugin.
  504. */
  505. public function activateDeactivateAll($h, $enabled = 0)
  506. { // 0 = deactivate, 1 = activate
  507. // Clear the database cache to ensure plugins and hooks are up-to-date.
  508. $h->deleteFiles(CACHE . 'db_cache');
  509. // Clear the css/js cache to ensure any new ones get included
  510. $h->deleteFiles(CACHE . 'css_js_cache');
  511. $h->messages['db, css caches cleared'] = 'alert-info';
  512. // if you want to deactivate, just go ahead and do it:
  513. if ($enabled == 0) {
  514. $sql = "UPDATE " . TABLE_PLUGINS . " SET plugin_enabled = %d, plugin_updateby = %d";
  515. $h->db->query($h->db->prepare($sql, $enabled, $h->currentUser->id));
  516. $h->messages[$h->lang("admin_plugins_deactivated")] = 'green';
  517. return false;
  518. //$active_plugins = $this->activePlugins($h->db, '*', 1);
  519. }
  520. // if you want to activate, find all the inactive plugins
  521. if ($enabled == 1) { $active_plugins = $this->activePlugins($h->db, '*', 0); }
  522. if (!$active_plugins) { return false; }
  523. /* The problem with upgrading plugins is many of them require other plugins to work,
  524. therefore half the plugins can't be upgraded if the upgrade is attempted in a
  525. random order. So let's minimize the problem by sorting the plugins by number of
  526. requirements, i.e. plugins that have no requirements (Users, Submit, Sidebar Widgets)
  527. are upgraded first, then plugins with one requirement... and finally Pligg Importer,
  528. which has about 7 requirements. */
  529. $i = 0;
  530. foreach ($active_plugins as $active) {
  531. $h->plugin->folder = $active->plugin_folder;
  532. $ordered[$i]['name'] = $active->plugin_folder;
  533. if (!$active->plugin_requires) {
  534. $ordered[$i]['req_count'] = 0;
  535. } else {
  536. $requires = explode(', ', $active->plugin_requires);
  537. $ordered[$i]['req_count'] = count($requires);
  538. }
  539. $i++;
  540. }
  541. $ordered = sksort($ordered, 'req_count', 'int', true);
  542. foreach ($ordered as $ord) {
  543. $plugin_row = $h->db->get_row($h->db->prepare("SELECT plugin_folder, plugin_enabled FROM " . TABLE_PLUGINS . " WHERE plugin_folder = %s", $ord['name']));
  544. $h->plugin->folder = $plugin_row->plugin_folder;
  545. $this->activateDeactivateDo($h, $plugin_row, $enabled);
  546. }
  547. }
  548. /**
  549. * Enables or disables all plugins, installing if necessary
  550. *
  551. * @param int $enabled
  552. * Note: This function does not uninstall/delete a plugin.
  553. */
  554. public function activateDeactivateDo($h, $plugin, $enabled = 0)
  555. { // 0 = deactivate, 1 = activate
  556. // The plugin is already installed. Activate or deactivate according to $enabled (the user's action).
  557. if ($plugin->plugin_enabled == $enabled) { return false; } // only update if we're changing the enabled value.
  558. $sql = "UPDATE " . TABLE_PLUGINS . " SET plugin_enabled = %d, plugin_updateby = %d WHERE plugin_folder = %s";
  559. $h->db->query($h->db->prepare($sql, $enabled, $h->currentUser->id, $h->plugin->folder));
  560. if ($enabled == 1) { // Activating now...
  561. // Get plugin version from the database...
  562. $db_version = $h->getPluginVersion($h->plugin->folder);
  563. // Get plugin version from the file....
  564. $plugin_metadata = $this->readPluginMeta($h->plugin->folder);
  565. $file_version = $plugin_metadata['version'];
  566. // If file version is newer the the current plugin version, then upgrade...
  567. if (version_compare($file_version, $db_version, '>')) {
  568. $this->upgrade($h); // runs the install function and shows "upgraded!" message instead of "installed".
  569. } else {
  570. // else simply show an activated message...
  571. $h->messages[$h->lang("admin_plugins_activated")] = 'green';
  572. }
  573. // Force inclusion of a language file (if exists) because the
  574. // plugin isn't ready to include it itself yet.
  575. $h->includeLanguage();
  576. }
  577. if ($enabled == 0) {
  578. $h->messages[$h->lang("admin_plugins_deactivated")] = 'green';
  579. }
  580. $h->pluginHook('activate_deactivate', '', array('enabled' => $enabled));
  581. return $enabled;
  582. }
  583. /**
  584. * Get a list of active or inactive plugins (or their descriptions, etc.)
  585. *
  586. * @param string $select the table column to return
  587. * @param int $enabled 0 for inactive, 1 for active
  588. * @return array
  589. */
  590. public function activePlugins($db, $select = 'plugin_folder', $enabled = 1)
  591. {
  592. $sql = "SELECT $select FROM " . TABLE_PLUGINS . " WHERE plugin_enabled = %d";
  593. $active_plugins = $db->get_results($db->prepare($sql, $enabled));
  594. if ($active_plugins) { return $active_plugins; } else {return false; }
  595. }
  596. /**
  597. *
  598. */
  599. public function pluginReorder($h, $sort = '')
  600. {
  601. if (!$sort) return false;
  602. foreach($sort as $p => $id)
  603. {
  604. //print $p+1 . '=' . $id . '<br/>';
  605. // since array starts at 0 we need to add 1 to $p to get the sort order for saving to db
  606. $sql = "UPDATE " . TABLE_PLUGINS . " SET plugin_order = %d WHERE plugin_id = %d";
  607. //print $h->db->prepare($sql, $p+1, $id) . '<br/>';
  608. $h->db->query($h->db->prepare($sql, $p+1, $id));
  609. }
  610. //refresh cache and sort hooks
  611. $this->refreshPluginDetails($h);
  612. $this->sortPluginHooks($h);
  613. $h->clearCache('db_cache', false);
  614. return true;
  615. }
  616. /**
  617. * Updates plugin order and order of their hooks, i.e. changes the order
  618. * of plugins in pluginHook.
  619. *
  620. * @param int $order current order
  621. * @param string $arrow direction to move
  622. */
  623. public function pluginOrder($h, $order = 0, $arrow = "up")
  624. {
  625. if ($order == 0) {
  626. $h->messages[$h->lang('admin_plugins_order_zero')] = 'red';
  627. return false;
  628. }
  629. $this_plugin = $h->getPluginName();
  630. if ($arrow == "up")
  631. {
  632. // get row above
  633. $sql= "SELECT * FROM " . TABLE_PLUGINS . " WHERE plugin_order = %d";
  634. $row_above = $h->db->get_row($h->db->prepare($sql, ($order - 1)));
  635. if (!$row_above) {
  636. $h->messages[$this_plugin . " " . $h->lang('admin_plugins_order_first')] = 'red';
  637. return false;
  638. }
  639. if ($row_above->plugin_order == $order) {
  640. $h->messages[$h->lang('admin_plugins_order_above')] = 'red';
  641. return false;
  642. }
  643. // update row above
  644. $sql = "UPDATE " . TABLE_PLUGINS . " SET plugin_order = %d WHERE plugin_id = %d";
  645. $h->db->query($h->db->prepare($sql, ($row_above->plugin_order + 1), $row_above->plugin_id));
  646. // update current plugin
  647. $sql = "UPDATE " . TABLE_PLUGINS . " SET plugin_order = %d WHERE plugin_folder = %s";
  648. $h->db->query($h->db->prepare($sql, ($order - 1), $h->plugin->folder));
  649. }
  650. else
  651. {
  652. // get row below
  653. $sql= "SELECT * FROM " . TABLE_PLUGINS . " WHERE plugin_order = %d";
  654. $row_below = $h->db->get_row($h->db->prepare($sql, ($order + 1)));
  655. if (!$row_below) {
  656. $h->messages[$this_plugin . " " . $h->lang('admin_plugins_order_last')] = 'red';
  657. return false;
  658. }
  659. if ($row_below->plugin_order == $order) {
  660. $h->messages[$h->lang('admin_plugins_order_below')] = 'red';
  661. return false;
  662. }
  663. // update row above
  664. $sql = "UPDATE " . TABLE_PLUGINS . " SET plugin_order = %d WHERE plugin_id = %d";
  665. $h->db->query($h->db->prepare($sql, ($row_below->plugin_order - 1), $row_below->plugin_id));
  666. // update current plugin
  667. $sql = "UPDATE " . TABLE_PLUGINS . " SET plugin_order = %d WHERE plugin_folder = %s";
  668. $h->db->query($h->db->prepare($sql, ($order + 1), $h->plugin->folder));
  669. }
  670. $h->messages[$h->lang('admin_plugins_order_updated')] = 'green';
  671. // Re-sort all orders and remove any accidental gaps
  672. $this->refreshPluginOrder($h);
  673. $this->sortPluginHooks($h);
  674. return true;
  675. }
  676. /**
  677. * Refresh Plugin Details
  678. * Plugin Management updates often happen after $h->allPluginDetails has been filled.
  679. * This little hack clears the cached update time and refills $h->allPluginDetails
  680. */
  681. public function refreshPluginDetails($h)
  682. {
  683. unset($h->vars['last_updates']['plugins']);
  684. PluginFunctions::getAllPluginDetails($h);
  685. }
  686. /**
  687. * Update Plugins
  688. *
  689. * @param <type> $h
  690. */
  691. public function update($h)
  692. {
  693. $url = "http://hotaruplugins.com/zip/";
  694. $folder = $h->plugin->folder;
  695. $version= $h->cage->get->getHtmLawed('version');
  696. $findfolder = str_replace('_', '-', $folder);
  697. $version = str_replace('.', '-', $version);
  698. // pluginmanagement so its a plugin
  699. $url .= 'plugins';
  700. // add pluginfoler to the url as well
  701. $url .= '/' . $findfolder . '/';
  702. //print $url;
  703. // TODO
  704. // make temp folder the copy directory and unzip files here first
  705. // copy old folder somewhere and then bring in new one
  706. // before deleting zip and old folder totally
  707. //$copydir = CONTENT . "temp/";
  708. $copydir = PLUGINS;
  709. $file = $findfolder . "-" . $version . ".zip";
  710. // Create those directories if need be:
  711. if (! is_dir($copydir) && ! mkdir($copydir, 0777) ) {
  712. $h->messages['Failed to create temp directory.' . $copydir] = 'red';
  713. } else {
  714. //if ($h->debug) $h->messages['temp folder located'] = 'alert-info';
  715. }
  716. // get ftpsettings
  717. // $ftpserver = "api.hotarucms.org";
  718. // $ftppath = "/public_html/api/content/";
  719. // $ftpuser = "hotarorg";
  720. // $ftppass = "";
  721. if ($h->debug) $h->messages['setting copy directory as ' . $copydir] = 'alert-info';
  722. //$ftp_url = "ftp://" . $ftpuser . ":" . stripslashes($ftppass) . "@" . $ftpserver . $ftppath . $folder . "/" ;
  723. // check that we can access the remote plugin repo site via curl
  724. if ($this->fileCheckCurlConnection($url, $file) == 200) {
  725. $h->messages['File succesfully located on remote plugin server'] = 'alert-success';
  726. if ($write = is_writeable($copydir)) {
  727. //if ($h->debug) $h->messages['we will use php for file copy'] = 'alert-info';
  728. $this->filePhpWrite($h, $url, $file, $findfolder, $copydir);
  729. } else {
  730. //if ($h->debug) $h->messages['we will use ftp for file copy'] = 'alert-info';
  731. $h->messages['ftp copy not operational yet in this version of Hotaru CMS'] = 'red';
  732. //$this->fileFtpWrite($h, $url, $ftp_url, $file, $findfolder, $copydir);
  733. }
  734. } else {
  735. $h->messages[$file . $h->lang('admin_theme_fileexist_error')] = 'red';
  736. }
  737. // unzip
  738. if (file_exists( $copydir . $file)) {
  739. $h->messages['About to start the unzip process' . $copydir . $file] = 'alert-info';
  740. // check chmod
  741. if (!$write) { $this->fileFtpChmod($h, $ftp_url, $folder, '777'); }
  742. // Should we rename old files first and then bring in new ?
  743. $zipResult = $this->fileUnzip($h, $copydir . $file, $copydir);
  744. if (!$write) { $this->fileFtpChmod($h, $ftp_url, $folder, '755'); }
  745. if ($zipResult == 1) {
  746. // only delete zip file if we have been succesful ?
  747. //if ($h->debug) $h->messages['About to delete zip file'] = 'alert-info';
  748. if ($write) {
  749. //print "we can use PHP<br/>";
  750. $this->filePhpDelete($h, $file, $copydir);
  751. } else {
  752. //print "we will use FTP<br/>";
  753. $this->fileFtpDelete($h, $ftp_url, $file, $copydir);
  754. }
  755. } else {
  756. $h->messages['not deleting zip file as unzip failed'] = 'red';
  757. }
  758. } else {
  759. $h->messages[$h->lang('admin_theme_filecopy_error') . $file] = 'red';
  760. }
  761. }
  762. public function fileCheckCurlConnection($url, $file)
  763. {
  764. // create a new CURL resource
  765. $ch = curl_init();
  766. // set URL and other appropriate options
  767. curl_setopt($ch, CURLOPT_URL, $url . $file);
  768. curl_setopt($ch, CURLOPT_HEADER, false);
  769. curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
  770. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  771. set_time_limit(30); # 30 seconds for PHP
  772. curl_setopt($ch, CURLOPT_TIMEOUT, 30); # and also for CURL
  773. //don't fetch the actual page, you only want to check the connection is ok
  774. curl_setopt($ch, CURLOPT_NOBODY, true);
  775. $zipfile = curl_exec($ch);
  776. $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  777. curl_close($ch);
  778. //print 'checking directory is accesible: ' . $statusCode . '<br/>';
  779. return $statusCode;
  780. }
  781. public function filePhpWrite($h, $url, $file, $findfolder, $copydir )
  782. {
  783. // we can only get file if hotaruplugins is letting us access the zip folder
  784. // check for access first
  785. //$h->messages['url = ' . $url . $file] = 'alert-info';
  786. //$ch = curl_init($url . $file);
  787. //$fp = fopen($copydir . $file, "w");
  788. //
  789. //curl_setopt($ch, CURLOPT_FILE, $fp);
  790. //curl_setopt($ch, CURLOPT_HEADER, 0);
  791. //
  792. //curl_exec($ch);
  793. //curl_close($ch);
  794. //fclose($fp);
  795. if (1==1) {
  796. // create a new CURL resource
  797. $ch = curl_init();
  798. // set URL and other appropriate options
  799. curl_setopt($ch, CURLOPT_URL, $url . $file);
  800. curl_setopt($ch, CURLOPT_HEADER, false);
  801. curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
  802. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  803. set_time_limit(300); # 5 minutes for PHP
  804. curl_setopt($ch, CURLOPT_TIMEOUT, 300); # and also for CURL
  805. //don't fetch the actual page, you only want to check the connection is ok
  806. curl_setopt($ch, CURLOPT_NOBODY, true);
  807. $zipfile = curl_exec($ch);
  808. $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  809. if ($statusCode == 200) {
  810. if (is_writeable($copydir)) {
  811. //reset this from above
  812. curl_setopt($ch, CURLOPT_NOBODY, false);
  813. $outfile = @fopen($copydir . $file, 'wb');
  814. curl_setopt($ch, CURLOPT_FILE, $outfile);
  815. $handle =base64_encode(curl_exec ($ch));
  816. fclose($outfile);
  817. if ($handle) {
  818. $h->messages[$file . $h->lang('admin_theme_filecopy_success')] = 'green';
  819. } else {
  820. $h->messages['something went wrong getting base64 handle'];
  821. }
  822. } else {
  823. $h->messages[$h->lang('admin_theme_filecopy_error' . $file)] = 'red';
  824. }
  825. } else {
  826. $h->messages[$h->lang('admin_theme_fileexist_error' . $file)] = 'red';
  827. }
  828. curl_close($ch);
  829. }
  830. }
  831. public function fileUnzip($h, $file, $to)
  832. {
  833. //$h->messages[$file . $h->lang('admin_theme_filecopy_success')] = 'green';
  834. //$file = '/home/ipadrank/public_html/content/temp/metatags-0-3.zip';
  835. $z = new ZipArchive();
  836. $zopen = $z->open($file, ZIPARCHIVE::CHECKCONS);
  837. if ($h->debug) $h->messages['Attempt to unzip ' . $file] = 'alert-info';
  838. if ($zopen !== true) {
  839. $h->messages['Could not open zip file ' . $file] = 'red';
  840. return false;
  841. }
  842. // code from Wordpress with much appreciation
  843. for ( $i = 0; $i < $z->numFiles; $i++ ) {
  844. if ( ! $info = $z->statIndex($i) ) {
  845. $h->messages['Could not retrieve file from archive.' . $file] = 'red';
  846. return false;
  847. }
  848. if ( '__MACOSX/' === substr($info['name'], 0, 9) ) // Skip the OS X-created __MACOSX directory
  849. continue;
  850. if ( '/' == substr($info['name'], -1) ) // directory
  851. $needed_dirs[] = $to . rtrim($info['name'], '/');
  852. else
  853. $needed_dirs[] = $to . rtrim(dirname($info['name']),'/');
  854. }
  855. $needed_dirs = array_unique($needed_dirs);
  856. foreach ( $needed_dirs as $dir ) {
  857. // Check the parent folders of the folders all exist within the creation array.
  858. if ( rtrim($to,'/') == $dir ) // Skip over the working directory, We know this exists (or will exist)
  859. continue;
  860. if ( strpos($dir, $to) === false ) // If the directory is not within the working directory, Skip it
  861. continue;
  862. $parent_folder = dirname($dir);
  863. while ( !empty($parent_folder) && rtrim($to,'/') != $parent_folder && !in_array($parent_folder, $needed_dirs) ) {
  864. $needed_dirs[] = $parent_folder;
  865. $parent_folder = dirname($parent_folder);
  866. }
  867. }
  868. asort($needed_dirs);
  869. // Create those directories if need be:
  870. foreach ( $needed_dirs as $_dir ) {
  871. if (! is_dir($dir) && ! mkdir($_dir, 0777)) {// Only check to see if the Dir exists upon creation failure. Less I/O this way.
  872. $h->messages['Could not create directory.' . $dir] = 'red';
  873. return false;
  874. }
  875. }
  876. unset($needed_dirs);
  877. for ( $i = 0; $i < $z->numFiles; $i++ ) {
  878. if ( ! $info = $z->statIndex($i) ) {
  879. $h->messages['Could not retrieve file from archive.'] = 'red';
  880. return false;
  881. }
  882. if ( '/' == substr($info['name'], -1) ) // directory
  883. continue;
  884. if ( '__MACOSX/' === substr($info['name'], 0, 9) ) // Don't extract the OS X-created __MACOSX directory files
  885. continue;
  886. $contents = $z->getFromIndex($i);
  887. if ( false === $contents ) {
  888. $h->messages['Could not extract file from archive.' . $info['name']] = 'red';
  889. return false;
  890. }
  891. if ( ! file_put_contents( $to . $info['name'], $contents, 644) ) {
  892. $h->messages['Could not copy file.' . $info['filename']] = 'red';
  893. return false;
  894. }
  895. }
  896. // require_once(EXTENSIONS . 'pclZip/pclzip.lib.php');
  897. // $archive = new PclZip($copydir . $file);
  898. //
  899. // if (($list = $archive->extract(PCLZIP_OPT_PATH, PLUGINS)) == 0) {
  900. // $h->messages[$h->lang('admin_theme_unzip_error'] . $file) = 'red';
  901. // return false;
  902. // }
  903. $h->messages[$file . $h->lang('admin_theme_unzip_success')] = 'green';
  904. $z->close();
  905. return true;
  906. }
  907. public function folderDelete($h, $folder)
  908. {
  909. @chmod($folder, 666);
  910. $deleted = @unlink($folder);
  911. if (!$deleted) {
  912. $h->messages['folder could not be deleted before unzipping'] = 'yellow';
  913. } else {
  914. $h->messages['old folder deleted successfully'] = 'green';
  915. }
  916. }
  917. public function filePhpDelete($h, $file, $copydir)
  918. {
  919. @chmod($copydir . $file,666);
  920. $deleted = @unlink($copydir . $file);
  921. if (!$deleted) {
  922. $h->messages[$file . $h->lang('admin_theme_zipdelete_error')] = 'yellow';
  923. }
  924. }
  925. public function fileFtpChmod($h, $ftp_url, $folder, $permission)
  926. {// print "start chmod for " . $ftp_url;
  927. $ch = curl_init();
  928. curl_setopt($ch, CURLOPT_URL, $ftp_url);
  929. curl_setopt($ch, CURLOPT_RETURNTRANSFER, false);
  930. curl_setopt($ch, CURLOPT_POSTQUOTE, array("CHMOD " . $permission . ' ' . $folder));
  931. curl_exec($ch);
  932. if ($error = curl_error($ch)) {
  933. // write this to error log
  934. echo "<br/>Error: $error<br />\n";
  935. }
  936. $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  937. // 250 comes from FTP error code saying action completed ok
  938. if (!$statusCode == 250) {
  939. print "problem";
  940. }
  941. curl_close($ch);
  942. }
  943. public function fileFtpDelete($h, $ftp_url, $file, $copydir)
  944. {
  945. $ch = curl_init();
  946. curl_setopt($ch, CURLOPT_URL, $ftp_url . 'plugins/');
  947. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  948. curl_setopt($ch, CURLOPT_POSTQUOTE, array("DELE " . $file));
  949. curl_exec($ch);
  950. // if ($error = curl_error($ch)) {
  951. // // write this to error log
  952. // echo "<br/>Error: $error<br />\n";
  953. // }
  954. $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  955. // 250 comes from FTP error code saying action completed ok
  956. if (!$statusCode == 250) {
  957. $h->messages[$file . $h->lang('admin_theme_zipdelete_error')] = 'yellow';
  958. }
  959. curl_close($ch);
  960. }
  961. public function fileFtpWrite($h, $url, $ftp_url, $file, $folder, $copydir)
  962. {
  963. $BUFF="";
  964. $ch = curl_init();
  965. print "Checking FTP at " . $url . " to get file " . $file. "<br/>";
  966. curl_setopt($ch, CURLOPT_URL, $url . $file);
  967. // Set callback function for body
  968. curl_setopt($ch, CURLOPT_WRITEFUNCTION, array($this, 'read_body'));
  969. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
  970. curl_exec($ch);
  971. $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  972. if ($error = curl_error($ch)) {
  973. $h->messages[$h->lang('admin_theme_filecopy_permission_error')] = 'red';
  974. echo "Error: $error<br />\n";
  975. }
  976. print "<br/><br/>Trying to upload to: " .$ftp_url . 'plugins/' . $file;
  977. curl_setopt($ch, CURLOPT_URL, $ftp_url . 'plugins/' .$file);
  978. curl_setopt($ch, CURLOPT_UPLOAD, 1);
  979. #curl_setopt($ch, CURLOPT_INFILE, 0);
  980. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
  981. #curl_setopt($ch, CURLOPT_VERBOSE, 1);
  982. curl_setopt ($ch, CURLOPT_READFUNCTION, array($this, 'write_function'));
  983. // set size of the image, which isn't _mandatory_ but helps libcurl to do
  984. // extra error checking on the upload.
  985. #curl_setopt($ch, CURLOPT_INFILESIZE, filesize($localfile));
  986. curl_exec($ch);
  987. $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  988. if ($error = curl_error($ch)) {
  989. $h->messages[$h->lang('admin_theme_filecopy_permission_error')] = 'red';
  990. echo "Error: $error<br />\n";
  991. }
  992. curl_close($ch);
  993. return $error;
  994. }
  995. public function write_function($handle, $fd, $length)
  996. {
  997. global $BUF;
  998. $l = strlen($BUF);
  999. if ( $l > $length ) {
  1000. $part = substr($BUF, 0, $length);
  1001. $BUF = substr($BUF, $length);
  1002. } else {
  1003. $part = $BUF;
  1004. $BUF = "";
  1005. }
  1006. echo "<br/>Sent $l bytes<br/>\n";
  1007. return $part;
  1008. }
  1009. public function read_body($ch, $string)
  1010. {
  1011. global $BUF;
  1012. $length = strlen($string);
  1013. echo "Received $length bytes<br />\n";
  1014. $BUF=$BUF.$string;
  1015. return $length;
  1016. }
  1017. public function versionCheck($h)
  1018. {
  1019. $systeminfo = New SystemInfo();
  1020. $result = $systeminfo->plugin_version_getAll($h);
  1021. if ($result) {
  1022. $h->messages[$h->lang('admin_theme_version_check_completed')] = 'alert-success';
  1023. } else {
  1024. $h->messages[$h->lang('admin_theme_version_check_failed')] = 'alert-error';
  1025. }
  1026. }
  1027. }
  1028. ?>