PageRenderTime 45ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/joomla/libraries/joomla/installer/adapters/language.php

https://github.com/reechalee/joomla1.6
PHP | 594 lines | 403 code | 62 blank | 129 comment | 61 complexity | b83e7e614508b3c29ccc4058d17cedf1 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, BSD-3-Clause, JSON
  1. <?php
  2. /**
  3. * @version $Id: language.php 20457 2011-01-27 07:51:58Z infograf768 $
  4. * @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
  5. * @license GNU General Public License version 2 or later; see LICENSE.txt
  6. */
  7. // No direct access
  8. defined('JPATH_BASE') or die;
  9. jimport('joomla.base.adapterinstance');
  10. /**
  11. * Language installer
  12. *
  13. * @package Joomla.Framework
  14. * @subpackage Installer
  15. * @since 1.5
  16. */
  17. class JInstallerLanguage extends JAdapterInstance
  18. {
  19. /**
  20. * Core language pack flag
  21. * @access private
  22. * @var boolean
  23. */
  24. protected $_core = false;
  25. /**
  26. * Custom install method
  27. * Note: This behaves badly due to hacks made in the middle of 1.5.x to add
  28. * the ability to install multiple distinct packs in one install. The
  29. * preferred method is to use a package to install multiple language packs.
  30. *
  31. * @access public
  32. * @return boolean True on success
  33. * @since 1.5
  34. */
  35. public function install()
  36. {
  37. $source = $this->parent->getPath('source');
  38. if (!$source) {
  39. $this->parent->setPath('source', ($this->parent->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE) . '/language/'.$this->parent->extension->element);
  40. }
  41. $this->manifest = $this->parent->getManifest();
  42. $root = $this->manifest->document;
  43. // Get the client application target
  44. if ((string)$this->manifest->attributes()->client == 'both')
  45. {
  46. JError::raiseWarning(42, JText::_('JLIB_INSTALLER_ERROR_DEPRECATED_FORMAT'));
  47. $element = $this->manifest->site->files;
  48. if (!$this->_install('site', JPATH_SITE, 0, $element)) {
  49. return false;
  50. }
  51. $element = $this->manifest->administration->files;
  52. if (!$this->_install('administrator', JPATH_ADMINISTRATOR, 1, $element)) {
  53. return false;
  54. }
  55. // This causes an issue because we have two eid's, *sigh* nasty hacks!
  56. return true;
  57. }
  58. elseif ($cname = (string)$this->manifest->attributes()->client)
  59. {
  60. // Attempt to map the client to a base path
  61. jimport('joomla.application.helper');
  62. $client = JApplicationHelper::getClientInfo($cname, true);
  63. if ($client === null) {
  64. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT', JText::sprintf('JLIB_INSTALLER_ERROR_UNKNOWN_CLIENT_TYPE', $cname)));
  65. return false;
  66. }
  67. $basePath = $client->path;
  68. $clientId = $client->id;
  69. $element = $this->manifest->files;
  70. return $this->_install($cname, $basePath, $clientId, $element);
  71. }
  72. else
  73. {
  74. // No client attribute was found so we assume the site as the client
  75. $cname = 'site';
  76. $basePath = JPATH_SITE;
  77. $clientId = 0;
  78. $element = $this->manifest->files;
  79. return $this->_install($cname, $basePath, $clientId, $element);
  80. }
  81. }
  82. /**
  83. * Install function that is designed to handle individual clients
  84. */
  85. protected function _install($cname, $basePath, $clientId, &$element)
  86. {
  87. $this->manifest = $this->parent->getManifest();
  88. // Get the language name
  89. // Set the extensions name
  90. $name = JFilterInput::getInstance()->clean((string)$this->manifest->name, 'cmd');
  91. $this->set('name', $name);
  92. // Get the Language tag [ISO tag, eg. en-GB]
  93. $tag = (string)$this->manifest->tag;
  94. // Check if we found the tag - if we didn't, we may be trying to install from an older language package
  95. if ( ! $tag)
  96. {
  97. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT', JText::_('JLIB_INSTALLER_ERROR_NO_LANGUAGE_TAG')));
  98. return false;
  99. }
  100. $this->set('tag', $tag);
  101. // Set the language installation path
  102. $this->parent->setPath('extension_site', $basePath.DS.'language'.DS.$tag);
  103. // Do we have a meta file in the file list? In other words... is this a core language pack?
  104. if ($element && count($element->children()))
  105. {
  106. $files = $element->children();
  107. foreach ($files as $file) {
  108. if ((string)$file->attributes()->file == 'meta') {
  109. $this->_core = true;
  110. break;
  111. }
  112. }
  113. }
  114. // Either we are installing a core pack or a core pack must exist for the language we are installing.
  115. if (!$this->_core)
  116. {
  117. if (!JFile::exists($this->parent->getPath('extension_site').DS.$this->get('tag').'.xml')) {
  118. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT', JText::sprintf('JLIB_INSTALLER_ERROR_NO_CORE_LANGUAGE', $this->get('tag'))));
  119. return false;
  120. }
  121. }
  122. // If the language directory does not exist, lets create it
  123. $created = false;
  124. if (!file_exists($this->parent->getPath('extension_site')))
  125. {
  126. if (!$created = JFolder::create($this->parent->getPath('extension_site')))
  127. {
  128. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT', JText::sprintf('JLIB_INSTALLER_ERROR_CREATE_FOLDER_FAILED', $this->parent->getPath('extension_site'))));
  129. return false;
  130. }
  131. }
  132. else
  133. {
  134. // look for an update function or update tag
  135. $updateElement = $this->manifest->update;
  136. // upgrade manually set
  137. // update function available
  138. // update tag detected
  139. if ($this->parent->getUpgrade() || ($this->parent->manifestClass && method_exists($this->parent->manifestClass,'update')) || is_a($updateElement, 'JXMLElement')) {
  140. return $this->update(); // transfer control to the update function
  141. }
  142. else if (!$this->parent->getOverwrite())
  143. {
  144. // overwrite is set
  145. // we didn't have overwrite set, find an update function or find an update tag so lets call it safe
  146. if (file_exists($this->parent->getPath('extension_site'))) { // if the site exists say that
  147. JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ABORT', JText::sprintf('JLIB_INSTALLER_ERROR_FOLDER_IN_USE', $this->parent->getPath('extension_site'))));
  148. }
  149. else { // if the admin exists say that
  150. JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ABORT', JText::sprintf('JLIB_INSTALLER_ERROR_FOLDER_IN_USE', $this->parent->getPath('extension_administrator'))));
  151. }
  152. return false;
  153. }
  154. }
  155. /*
  156. * If we created the language directory and will want to remove it if we
  157. * have to roll back the installation, lets add it to the installation
  158. * step stack
  159. */
  160. if ($created) {
  161. $this->parent->pushStep(array ('type' => 'folder', 'path' => $this->parent->getPath('extension_site')));
  162. }
  163. // Copy all the necessary files
  164. if ($this->parent->parseFiles($element) === false)
  165. {
  166. // Install failed, rollback changes
  167. $this->parent->abort();
  168. return false;
  169. }
  170. // Parse optional tags
  171. $this->parent->parseMedia($this->manifest->media);
  172. // Copy all the necessary font files to the common pdf_fonts directory
  173. $this->parent->setPath('extension_site', $basePath.DS.'language'.DS.'pdf_fonts');
  174. $overwrite = $this->parent->setOverwrite(true);
  175. if ($this->parent->parseFiles($this->manifest->fonts) === false)
  176. {
  177. // Install failed, rollback changes
  178. $this->parent->abort();
  179. return false;
  180. }
  181. $this->parent->setOverwrite($overwrite);
  182. // Get the language description
  183. $description = (string)$this->manifest->description;
  184. if ($description) {
  185. $this->parent->set('message', JText::_($description));
  186. }
  187. else {
  188. $this->parent->set('message', '');
  189. }
  190. // Add an entry to the extension table with a whole heap of defaults
  191. $row = JTable::getInstance('extension');
  192. $row->set('name', $this->get('name'));
  193. $row->set('type', 'language');
  194. $row->set('element', $this->get('tag'));
  195. $row->set('folder', ''); // There is no folder for languages
  196. $row->set('enabled', 1);
  197. $row->set('protected', 0);
  198. $row->set('access', 0);
  199. $row->set('client_id', $clientId);
  200. $row->set('params', $this->parent->getParams());
  201. $row->set('manifest_cache', $this->parent->generateManifestCache());
  202. if (!$row->store())
  203. {
  204. // Install failed, roll back changes
  205. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT', $row->getError()));
  206. return false;
  207. }
  208. // Clobber any possible pending updates
  209. $update = JTable::getInstance('update');
  210. $uid = $update->find(Array('element'=>$this->get('tag'),
  211. 'type'=>'language',
  212. 'client_id'=>'',
  213. 'folder'=>''));
  214. if ($uid) {
  215. $update->delete($uid);
  216. }
  217. return $row->get('extension_id');
  218. }
  219. /**
  220. * Custom update method
  221. *
  222. * @return boolean True on success, false on failure
  223. * @since 1.6
  224. */
  225. public function update()
  226. {
  227. $xml = $this->parent->getManifest();
  228. $this->manifest = $xml;
  229. $cname = $xml->attributes()->client;
  230. // Attempt to map the client to a base path
  231. jimport('joomla.application.helper');
  232. $client = JApplicationHelper::getClientInfo($cname, true);
  233. if ($client === null || (empty($cname) && $cname !== 0))
  234. {
  235. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT', JText::sprintf('JLIB_INSTALLER_ERROR_UNKNOWN_CLIENT_TYPE', $cname)));
  236. return false;
  237. }
  238. $basePath = $client->path;
  239. $clientId = $client->id;
  240. // Get the language name
  241. // Set the extensions name
  242. $name = (string)$this->manifest->name;
  243. $name = JFilterInput::getInstance()->clean($name, 'cmd');
  244. $this->set('name', $name);
  245. // Get the Language tag [ISO tag, eg. en-GB]
  246. $tag = (string)$xml->tag;
  247. // Check if we found the tag - if we didn't, we may be trying to install from an older language package
  248. if (!$tag)
  249. {
  250. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT', JText::_('JLIB_INSTALLER_ERROR_NO_LANGUAGE_TAG')));
  251. return false;
  252. }
  253. $this->set('tag', $tag);
  254. $folder = $tag;
  255. // Set the language installation path
  256. $this->parent->setPath('extension_site', $basePath.DS.'language'.DS.$this->get('tag'));
  257. // Do we have a meta file in the file list? In other words... is this a core language pack?
  258. if (count($xml->files->children()))
  259. {
  260. foreach ($xml->files->children() as $file)
  261. {
  262. if ((string)$file->attributes()->file == 'meta')
  263. {
  264. $this->_core = true;
  265. break;
  266. }
  267. }
  268. }
  269. // Either we are installing a core pack or a core pack must exist for the language we are installing.
  270. if (!$this->_core)
  271. {
  272. if (!JFile::exists($this->parent->getPath('extension_site').DS.$this->get('tag').'.xml'))
  273. {
  274. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT', JText::sprintf('JLIB_INSTALLER_ERROR_NO_CORE_LANGUAGE', $this->get('tag'))));
  275. return false;
  276. }
  277. }
  278. // Copy all the necessary files
  279. if ($this->parent->parseFiles($xml->files) === false)
  280. {
  281. // Install failed, rollback changes
  282. $this->parent->abort();
  283. return false;
  284. }
  285. // Parse optional tags
  286. $this->parent->parseMedia($xml->media);
  287. // Copy all the necessary font files to the common pdf_fonts directory
  288. $this->parent->setPath('extension_site', $basePath.DS.'language'.DS.'pdf_fonts');
  289. $overwrite = $this->parent->setOverwrite(true);
  290. if ($this->parent->parseFiles($xml->fonts) === false)
  291. {
  292. // Install failed, rollback changes
  293. $this->parent->abort();
  294. return false;
  295. }
  296. $this->parent->setOverwrite($overwrite);
  297. // Get the language description and set it as message
  298. $this->parent->set('message', (string)$xml->description);
  299. /**
  300. * ---------------------------------------------------------------------------------------------
  301. * Finalization and Cleanup Section
  302. * ---------------------------------------------------------------------------------------------
  303. */
  304. // Clobber any possible pending updates
  305. $update = JTable::getInstance('update');
  306. $uid = $update->find(Array('element'=>$this->get('tag'),
  307. 'type'=>'language',
  308. 'client_id'=>$clientId));
  309. if ($uid)
  310. {
  311. $update->delete($uid);
  312. }
  313. // Update an entry to the extension table
  314. $row = JTable::getInstance('extension');
  315. $eid = $row->find(Array('element'=>strtolower($this->get('tag')),
  316. 'type'=>'language', 'client_id'=>$clientId));
  317. if ($eid) {
  318. $row->load($eid);
  319. }
  320. else
  321. {
  322. // set the defaults
  323. $row->set('folder', ''); // There is no folder for language
  324. $row->set('enabled', 1);
  325. $row->set('protected', 0);
  326. $row->set('access', 0);
  327. $row->set('client_id', $clientId);
  328. $row->set('params', $this->parent->getParams());
  329. }
  330. $row->set('name', $this->get('name'));
  331. $row->set('type', 'language');
  332. $row->set('element', $this->get('tag'));
  333. $row->set('manifest_cache', $this->parent->generateManifestCache());
  334. if (!$row->store())
  335. {
  336. // Install failed, roll back changes
  337. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT', $row->getError()));
  338. return false;
  339. }
  340. // And now we run the postflight
  341. ob_start();
  342. ob_implicit_flush(false);
  343. if ($this->parent->manifestClass && method_exists($this->parent->manifestClass,'postflight'))
  344. {
  345. $this->parent->manifestClass->postflight('update', $this);
  346. }
  347. $msg .= ob_get_contents(); // append messages
  348. ob_end_clean();
  349. if ($msg != '') {
  350. $this->parent->set('extension_message', $msg);
  351. }
  352. return $row->get('extension_id');
  353. }
  354. /**
  355. * Custom uninstall method
  356. *
  357. * @param string $tag The tag of the language to uninstall
  358. * @param int $clientId The id of the client (unused)
  359. * @return mixed Return value for uninstall method in component uninstall file
  360. * @since 1.5
  361. */
  362. public function uninstall($eid)
  363. {
  364. // load up the extension details
  365. $extension = JTable::getInstance('extension');
  366. $extension->load($eid);
  367. // grab a copy of the client details
  368. $client = JApplicationHelper::getClientInfo($extension->get('client_id'));
  369. // check the element isn't blank to prevent nuking the languages directory...just in case
  370. $element = $extension->get('element');
  371. if (empty($element))
  372. {
  373. JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_LANG_UNINSTALL_ELEMENT_EMPTY'));
  374. return false;
  375. }
  376. // verify that it's not the default language for that client
  377. $params = JComponentHelper::getParams('com_languages');
  378. if ($params->get($client->name)==$element) {
  379. JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_LANG_UNINSTALL_DEFAULT'));
  380. return false;
  381. }
  382. // construct the path from the client, the language and the extension element name
  383. $path = $client->path.DS.'language'.DS.$element;
  384. // Get the package manifest object and remove media
  385. $this->parent->setPath('source', $path);
  386. // We do findManifest to avoid problem when uninstalling a list of extension: getManifest cache its manifest file
  387. $this->parent->findManifest();
  388. $this->manifest = $this->parent->getManifest();
  389. $this->parent->removeFiles($this->manifest->media);
  390. // check it exists
  391. if (!JFolder::exists($path))
  392. {
  393. // if the folder doesn't exist lets just nuke the row as well and presume the user killed it for us
  394. $extension->delete();
  395. JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_LANG_UNINSTALL_PATH_EMPTY'));
  396. return false;
  397. }
  398. if (!JFolder::delete($path))
  399. {
  400. // if deleting failed we'll leave the extension entry in tact just in case
  401. JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_LANG_UNINSTALL_DIRECTORY'));
  402. return false;
  403. }
  404. // Remove the extension table entry
  405. $extension->delete();
  406. // Setting the language of users which have this language as the default language
  407. $db = JFactory::getDbo();
  408. $query=$db->getQuery(true);
  409. $query->from('#__users');
  410. $query->select('*');
  411. $db->setQuery($query);
  412. $users = $db->loadObjectList();
  413. if($client->name == 'administrator') {
  414. $param_name = 'admin_language';
  415. } else {
  416. $param_name = 'language';
  417. }
  418. $count = 0;
  419. foreach ($users as $user) {
  420. $registry = new JRegistry;
  421. $registry->loadJSON($user->params);
  422. if ($registry->get($param_name)==$element) {
  423. $registry->set($param_name,'');
  424. $query=$db->getQuery(true);
  425. $query->update('#__users');
  426. $query->set('params='.$db->quote($registry));
  427. $query->where('id='.(int)$user->id);
  428. $db->setQuery($query);
  429. $db->query();
  430. $count = $count + 1;
  431. }
  432. }
  433. if (!empty($count)) {
  434. JError::raiseNotice(500, JText::plural('JLIB_INSTALLER_NOTICE_LANG_RESET_USERS', $count));
  435. }
  436. // All done!
  437. return true;
  438. }
  439. /**
  440. * Custom discover method
  441. * Finds language files
  442. */
  443. public function discover()
  444. {
  445. $results = Array();
  446. $site_languages = JFolder::folders(JPATH_SITE.DS.'language');
  447. $admin_languages = JFolder::folders(JPATH_ADMINISTRATOR.DS.'language');
  448. foreach ($site_languages as $language)
  449. {
  450. if (file_exists(JPATH_SITE.DS.'language'.DS.$language.DS.$language.'.xml'))
  451. {
  452. $manifest_details = JApplicationHelper::parseXMLInstallFile(JPATH_SITE.DS.'language'.DS.$language.DS.$language.'.xml');
  453. $extension = JTable::getInstance('extension');
  454. $extension->set('type', 'language');
  455. $extension->set('client_id', 0);
  456. $extension->set('element', $language);
  457. $extension->set('name', $language);
  458. $extension->set('state', -1);
  459. $extension->set('manifest_cache', json_encode($manifest_details));
  460. $results[] = $extension;
  461. }
  462. }
  463. foreach ($admin_languages as $language)
  464. {
  465. if (file_exists(JPATH_ADMINISTRATOR.DS.'language'.DS.$language.DS.$language.'.xml'))
  466. {
  467. $manifest_details = JApplicationHelper::parseXMLInstallFile(JPATH_ADMINISTRATOR.DS.'language'.DS.$language.DS.$language.'.xml');
  468. $extension = JTable::getInstance('extension');
  469. $extension->set('type', 'language');
  470. $extension->set('client_id', 1);
  471. $extension->set('element', $language);
  472. $extension->set('name', $language);
  473. $extension->set('state', -1);
  474. $extension->set('manifest_cache', json_encode($manifest_details));
  475. $results[] = $extension;
  476. }
  477. }
  478. return $results;
  479. }
  480. /**
  481. * Custom discover install method
  482. * Basically updates the manifest cache and leaves everything alone
  483. */
  484. public function discover_install()
  485. {
  486. // Need to find to find where the XML file is since we don't store this normally
  487. $client = JApplicationHelper::getClientInfo($this->parent->extension->client_id);
  488. $short_element = $this->parent->extension->element;
  489. $manifestPath = $client->path . DS . 'language'. DS . $short_element . DS . $short_element . '.xml';
  490. $this->parent->manifest = $this->parent->isManifest($manifestPath);
  491. $this->parent->setPath('manifest', $manifestPath);
  492. $this->parent->setPath('source', $client->path . DS . 'language'. DS . $short_element);
  493. $this->parent->setPath('extension_root', $this->parent->getPath('source'));
  494. $manifest_details = JApplicationHelper::parseXMLInstallFile($this->parent->getPath('manifest'));
  495. $this->parent->extension->manifest_cache = json_encode($manifest_details);
  496. $this->parent->extension->state = 0;
  497. $this->parent->extension->name = $manifest_details['name'];
  498. $this->parent->extension->enabled = 1;
  499. //$this->parent->extension->params = $this->parent->getParams();
  500. try {
  501. $this->parent->extension->store();
  502. }
  503. catch(JException $e)
  504. {
  505. JError::raiseWarning(101, JText::_('JLIB_INSTALLER_ERROR_LANG_DISCOVER_STORE_DETAILS'));
  506. return false;
  507. }
  508. return $this->parent->extension->get('extension_id');
  509. }
  510. /**
  511. * Refreshes the extension table cache
  512. * @return boolean result of operation, true if updated, false on failure
  513. * @since 1.6
  514. */
  515. public function refreshManifestCache()
  516. {
  517. $client = JApplicationHelper::getClientInfo($this->parent->extension->client_id);
  518. $manifestPath = $client->path . DS . 'language'. DS . $this->parent->extension->element . DS . $this->parent->extension->element . '.xml';
  519. $this->parent->manifest = $this->parent->isManifest($manifestPath);
  520. $this->parent->setPath('manifest', $manifestPath);
  521. $manifest_details = JApplicationHelper::parseXMLInstallFile($this->parent->getPath('manifest'));
  522. $this->parent->extension->manifest_cache = json_encode($manifest_details);
  523. $this->parent->extension->name = $manifest_details['name'];
  524. if ($this->parent->extension->store()) {
  525. return true;
  526. }
  527. else {
  528. JError::raiseWarning(101, JText::_('JLIB_INSTALLER_ERROR_MOD_REFRESH_MANIFEST_CACHE'));
  529. return false;
  530. }
  531. }
  532. }