PageRenderTime 48ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/libraries/legacy/installer/adapters/file.php

http://github.com/joomla/joomla-platform
PHP | 797 lines | 471 code | 144 blank | 182 comment | 66 complexity | 36a963b3e99c204d8131ef1d9b78823c MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. <?php
  2. /**
  3. * @package Joomla.Platform
  4. * @subpackage Installer
  5. *
  6. * @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE
  8. */
  9. defined('JPATH_PLATFORM') or die;
  10. jimport('joomla.installer.filemanifest');
  11. jimport('joomla.base.adapterinstance');
  12. jimport('joomla.filesystem.folder');
  13. /**
  14. * File installer
  15. *
  16. * @package Joomla.Platform
  17. * @subpackage Installer
  18. * @since 11.1
  19. * @deprecated 13.3
  20. */
  21. class JInstallerFile extends JAdapterInstance
  22. {
  23. protected $route = 'install';
  24. /**
  25. * Custom loadLanguage method
  26. *
  27. * @param string $path The path on which to find language files.
  28. *
  29. * @return void
  30. *
  31. * @since 11.1
  32. */
  33. public function loadLanguage($path)
  34. {
  35. $this->manifest = $this->parent->getManifest();
  36. $extension = 'files_' . str_replace('files_', '', strtolower(JFilterInput::getInstance()->clean((string) $this->manifest->name, 'cmd')));
  37. $lang = JFactory::getLanguage();
  38. $source = $path;
  39. $lang->load($extension . '.sys', $source, null, false, false)
  40. || $lang->load($extension . '.sys', JPATH_SITE, null, false, false)
  41. || $lang->load($extension . '.sys', $source, $lang->getDefault(), false, false)
  42. || $lang->load($extension . '.sys', JPATH_SITE, $lang->getDefault(), false, false);
  43. }
  44. /**
  45. * Custom install method
  46. *
  47. * @return boolean True on success
  48. *
  49. * @since 11.1
  50. */
  51. public function install()
  52. {
  53. // Get the extension manifest object
  54. $this->manifest = $this->parent->getManifest();
  55. /*
  56. * ---------------------------------------------------------------------------------------------
  57. * Manifest Document Setup Section
  58. * ---------------------------------------------------------------------------------------------
  59. */
  60. // Set the extension's name
  61. $name = JFilterInput::getInstance()->clean((string) $this->manifest->name, 'string');
  62. $this->set('name', $name);
  63. // Set element
  64. $manifestPath = JPath::clean($this->parent->getPath('manifest'));
  65. $element = preg_replace('/\.xml/', '', basename($manifestPath));
  66. $this->set('element', $element);
  67. // Get the component description
  68. $description = (string) $this->manifest->description;
  69. if ($description)
  70. {
  71. $this->parent->set('message', JText::_($description));
  72. }
  73. else
  74. {
  75. $this->parent->set('message', '');
  76. }
  77. // Check if the extension by the same name is already installed
  78. if ($this->extensionExistsInSystem($element))
  79. {
  80. // Package with same name already exists
  81. if (!$this->parent->isOverwrite())
  82. {
  83. // We're not overwriting so abort
  84. $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_FILE_SAME_NAME'));
  85. return false;
  86. }
  87. else
  88. {
  89. // Swap to the update route
  90. $this->route = 'update';
  91. }
  92. }
  93. // Set the file root path
  94. $this->parent->setPath('extension_root', JPATH_MANIFESTS . '/files/' . $this->get('element'));
  95. /**
  96. * ---------------------------------------------------------------------------------------------
  97. * Installer Trigger Loading
  98. * ---------------------------------------------------------------------------------------------
  99. */
  100. // If there is an manifest class file, lets load it; we'll copy it later (don't have dest yet)
  101. $this->scriptElement = $this->manifest->scriptfile;
  102. $manifestScript = (string) $this->manifest->scriptfile;
  103. if ($manifestScript)
  104. {
  105. $manifestScriptFile = $this->parent->getPath('source') . '/' . $manifestScript;
  106. if (is_file($manifestScriptFile))
  107. {
  108. // Load the file
  109. include_once $manifestScriptFile;
  110. }
  111. // Set the class name
  112. $classname = $element . 'InstallerScript';
  113. if (class_exists($classname))
  114. {
  115. // Create a new instance
  116. $this->parent->manifestClass = new $classname($this);
  117. // And set this so we can copy it later
  118. $this->set('manifest_script', $manifestScript);
  119. }
  120. }
  121. // Run preflight if possible (since we know we're not an update)
  122. ob_start();
  123. ob_implicit_flush(false);
  124. if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'preflight'))
  125. {
  126. if ($this->parent->manifestClass->preflight($this->route, $this) === false)
  127. {
  128. // Install failed, rollback changes
  129. $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_FILE_INSTALL_CUSTOM_INSTALL_FAILURE'));
  130. return false;
  131. }
  132. }
  133. // Create msg object; first use here
  134. $msg = ob_get_contents();
  135. ob_end_clean();
  136. // Populate File and Folder List to copy
  137. $this->populateFilesAndFolderList();
  138. /*
  139. * ---------------------------------------------------------------------------------------------
  140. * Filesystem Processing Section
  141. * ---------------------------------------------------------------------------------------------
  142. */
  143. // Now that we have folder list, lets start creating them
  144. foreach ($this->folderList as $folder)
  145. {
  146. if (!JFolder::exists($folder))
  147. {
  148. if (!$created = JFolder::create($folder))
  149. {
  150. JLog::add(JText::sprintf('JLIB_INSTALLER_ABORT_FILE_INSTALL_FAIL_SOURCE_DIRECTORY', $folder), JLog::WARNING, 'jerror');
  151. // If installation fails, rollback
  152. $this->parent->abort();
  153. return false;
  154. }
  155. // Since we created a directory and will want to remove it if we have to roll back.
  156. // The installation due to some errors, let's add it to the installation step stack.
  157. if ($created)
  158. {
  159. $this->parent->pushStep(array('type' => 'folder', 'path' => $folder));
  160. }
  161. }
  162. }
  163. // Now that we have file list, let's start copying them
  164. $this->parent->copyFiles($this->fileList);
  165. // Parse optional tags
  166. $this->parent->parseLanguages($this->manifest->languages);
  167. /**
  168. * ---------------------------------------------------------------------------------------------
  169. * Finalization and Cleanup Section
  170. * ---------------------------------------------------------------------------------------------
  171. */
  172. // Get a database connector object
  173. $db = $this->parent->getDbo();
  174. /*
  175. * Check to see if a file extension by the same name is already installed
  176. * If it is, then update the table because if the files aren't there
  177. * we can assume that it was (badly) uninstalled
  178. * If it isn't, add an entry to extensions
  179. */
  180. $query = $db->getQuery(true);
  181. $query->select($query->qn('extension_id'))
  182. ->from($query->qn('#__extensions'));
  183. $query->where($query->qn('type') . ' = ' . $query->q('file'))
  184. ->where($query->qn('element') . ' = ' . $query->q($element));
  185. $db->setQuery($query);
  186. try
  187. {
  188. $db->execute();
  189. }
  190. catch (RuntimeException $e)
  191. {
  192. // Install failed, roll back changes
  193. $this->parent->abort(
  194. JText::sprintf('JLIB_INSTALLER_ABORT_FILE_ROLLBACK', JText::_('JLIB_INSTALLER_' . $this->route), $db->stderr(true))
  195. );
  196. return false;
  197. }
  198. $id = $db->loadResult();
  199. $row = JTable::getInstance('extension');
  200. if ($id)
  201. {
  202. // Load the entry and update the manifest_cache
  203. $row->load($id);
  204. // Update name
  205. $row->set('name', $this->get('name'));
  206. // Update manifest
  207. $row->manifest_cache = $this->parent->generateManifestCache();
  208. if (!$row->store())
  209. {
  210. // Install failed, roll back changes
  211. $this->parent->abort(
  212. JText::sprintf('JLIB_INSTALLER_ABORT_FILE_ROLLBACK', JText::_('JLIB_INSTALLER_' . $this->route), $db->stderr(true))
  213. );
  214. return false;
  215. }
  216. }
  217. else
  218. {
  219. // Add an entry to the extension table with a whole heap of defaults
  220. $row->set('name', $this->get('name'));
  221. $row->set('type', 'file');
  222. $row->set('element', $this->get('element'));
  223. // There is no folder for files so leave it blank
  224. $row->set('folder', '');
  225. $row->set('enabled', 1);
  226. $row->set('protected', 0);
  227. $row->set('access', 0);
  228. $row->set('client_id', 0);
  229. $row->set('params', '');
  230. $row->set('system_data', '');
  231. $row->set('manifest_cache', $this->parent->generateManifestCache());
  232. if (!$row->store())
  233. {
  234. // Install failed, roll back changes
  235. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_FILE_INSTALL_ROLLBACK', $db->stderr(true)));
  236. return false;
  237. }
  238. // Since we have created a module item, we add it to the installation step stack
  239. // so that if we have to rollback the changes we can undo it.
  240. $this->parent->pushStep(array('type' => 'extension', 'extension_id' => $row->extension_id));
  241. }
  242. // Let's run the queries for the file
  243. if (strtolower($this->route) == 'install')
  244. {
  245. $result = $this->parent->parseSQLFiles($this->manifest->install->sql);
  246. if ($result === false)
  247. {
  248. // Install failed, rollback changes
  249. $this->parent->abort(
  250. JText::sprintf('JLIB_INSTALLER_ABORT_FILE_INSTALL_SQL_ERROR', JText::_('JLIB_INSTALLER_' . $this->route), $db->stderr(true))
  251. );
  252. return false;
  253. }
  254. // Set the schema version to be the latest update version
  255. if ($this->manifest->update)
  256. {
  257. $this->parent->setSchemaVersion($this->manifest->update->schemas, $row->extension_id);
  258. }
  259. }
  260. elseif (strtolower($this->route) == 'update')
  261. {
  262. if ($this->manifest->update)
  263. {
  264. $result = $this->parent->parseSchemaUpdates($this->manifest->update->schemas, $row->extension_id);
  265. if ($result === false)
  266. {
  267. // Install failed, rollback changes
  268. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_FILE_UPDATE_SQL_ERROR', $db->stderr(true)));
  269. return false;
  270. }
  271. }
  272. }
  273. // Try to run the script file's custom method based on the route
  274. ob_start();
  275. ob_implicit_flush(false);
  276. if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, $this->route))
  277. {
  278. if ($this->parent->manifestClass->{$this->route}($this) === false)
  279. {
  280. // Install failed, rollback changes
  281. $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_FILE_INSTALL_CUSTOM_INSTALL_FAILURE'));
  282. return false;
  283. }
  284. }
  285. // Append messages
  286. $msg .= ob_get_contents();
  287. ob_end_clean();
  288. // Lastly, we will copy the manifest file to its appropriate place.
  289. $manifest = array();
  290. $manifest['src'] = $this->parent->getPath('manifest');
  291. $manifest['dest'] = JPATH_MANIFESTS . '/files/' . basename($this->parent->getPath('manifest'));
  292. if (!$this->parent->copyFiles(array($manifest), true))
  293. {
  294. // Install failed, rollback changes
  295. $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_FILE_INSTALL_COPY_SETUP'));
  296. return false;
  297. }
  298. // If there is a manifest script, let's copy it.
  299. if ($this->get('manifest_script'))
  300. {
  301. // First, we have to create a folder for the script if one isn't present
  302. if (!file_exists($this->parent->getPath('extension_root')))
  303. {
  304. JFolder::create($this->parent->getPath('extension_root'));
  305. }
  306. $path['src'] = $this->parent->getPath('source') . '/' . $this->get('manifest_script');
  307. $path['dest'] = $this->parent->getPath('extension_root') . '/' . $this->get('manifest_script');
  308. if (!file_exists($path['dest']) || $this->parent->isOverwrite())
  309. {
  310. if (!$this->parent->copyFiles(array($path)))
  311. {
  312. // Install failed, rollback changes
  313. $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_PACKAGE_INSTALL_MANIFEST'));
  314. return false;
  315. }
  316. }
  317. }
  318. // Clobber any possible pending updates
  319. $update = JTable::getInstance('update');
  320. $uid = $update->find(
  321. array('element' => $this->get('element'), 'type' => 'file', 'client_id' => '', 'folder' => '')
  322. );
  323. if ($uid)
  324. {
  325. $update->delete($uid);
  326. }
  327. // And now we run the postflight
  328. ob_start();
  329. ob_implicit_flush(false);
  330. if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'postflight'))
  331. {
  332. $this->parent->manifestClass->postflight($this->route, $this);
  333. }
  334. // Append messages
  335. $msg .= ob_get_contents();
  336. ob_end_clean();
  337. if ($msg != '')
  338. {
  339. $this->parent->set('extension_message', $msg);
  340. }
  341. return $row->get('extension_id');
  342. }
  343. /**
  344. * Custom update method
  345. *
  346. * @return boolean True on success
  347. *
  348. * @since 11.1
  349. */
  350. public function update()
  351. {
  352. // Set the overwrite setting
  353. $this->parent->setOverwrite(true);
  354. $this->parent->setUpgrade(true);
  355. $this->route = 'update';
  356. // ...and adds new files
  357. return $this->install();
  358. }
  359. /**
  360. * Custom uninstall method
  361. *
  362. * @param string $id The id of the file to uninstall
  363. *
  364. * @return boolean True on success
  365. *
  366. * @since 11.1
  367. */
  368. public function uninstall($id)
  369. {
  370. $row = JTable::getInstance('extension');
  371. if (!$row->load($id))
  372. {
  373. JLog::add(JText::_('JLIB_INSTALLER_ERROR_FILE_UNINSTALL_LOAD_ENTRY'), JLog::WARNING, 'jerror');
  374. return false;
  375. }
  376. if ($row->protected)
  377. {
  378. JLog::add(JText::_('JLIB_INSTALLER_ERROR_FILE_UNINSTALL_WARNCOREFILE'), JLog::WARNING, 'jerror');
  379. return false;
  380. }
  381. $retval = true;
  382. $manifestFile = JPATH_MANIFESTS . '/files/' . $row->element . '.xml';
  383. // Because files may not have their own folders we cannot use the standard method of finding an installation manifest
  384. if (file_exists($manifestFile))
  385. {
  386. // Set the files root path
  387. $this->parent->setPath('extension_root', JPATH_MANIFESTS . '/files/' . $row->element);
  388. $xml = simplexml_load_file($manifestFile);
  389. // If we cannot load the XML file return null
  390. if (!$xml)
  391. {
  392. JLog::add(JText::_('JLIB_INSTALLER_ERROR_FILE_UNINSTALL_LOAD_MANIFEST'), JLog::WARNING, 'jerror');
  393. return false;
  394. }
  395. // Check for a valid XML root tag.
  396. if ($xml->getName() != 'extension')
  397. {
  398. JLog::add(JText::_('JLIB_INSTALLER_ERROR_FILE_UNINSTALL_INVALID_MANIFEST'), JLog::WARNING, 'jerror');
  399. return false;
  400. }
  401. $this->manifest = $xml;
  402. // If there is an manifest class file, let's load it
  403. $this->scriptElement = $this->manifest->scriptfile;
  404. $manifestScript = (string) $this->manifest->scriptfile;
  405. if ($manifestScript)
  406. {
  407. $manifestScriptFile = $this->parent->getPath('extension_root') . '/' . $manifestScript;
  408. if (is_file($manifestScriptFile))
  409. {
  410. // Load the file
  411. include_once $manifestScriptFile;
  412. }
  413. // Set the class name
  414. $classname = $row->element . 'InstallerScript';
  415. if (class_exists($classname))
  416. {
  417. // Create a new instance
  418. $this->parent->manifestClass = new $classname($this);
  419. // And set this so we can copy it later
  420. $this->set('manifest_script', $manifestScript);
  421. }
  422. }
  423. ob_start();
  424. ob_implicit_flush(false);
  425. // Run uninstall if possible
  426. if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'uninstall'))
  427. {
  428. $this->parent->manifestClass->uninstall($this);
  429. }
  430. $msg = ob_get_contents();
  431. ob_end_clean();
  432. if ($msg != '')
  433. {
  434. $this->parent->set('extension_message', $msg);
  435. }
  436. $db = JFactory::getDbo();
  437. // Let's run the uninstall queries for the extension
  438. $result = $this->parent->parseSQLFiles($this->manifest->uninstall->sql);
  439. if ($result === false)
  440. {
  441. // Install failed, rollback changes
  442. JLog::add(JText::sprintf('JLIB_INSTALLER_ERROR_FILE_UNINSTALL_SQL_ERROR', $db->stderr(true)), JLog::WARNING, 'jerror');
  443. $retval = false;
  444. }
  445. // Remove the schema version
  446. $query = $db->getQuery(true);
  447. $query->delete()
  448. ->from('#__schemas')
  449. ->where('extension_id = ' . $row->extension_id);
  450. $db->setQuery($query);
  451. $db->execute();
  452. // Loop through all elements and get list of files and folders
  453. foreach ($xml->fileset->files as $eFiles)
  454. {
  455. $folder = (string) $eFiles->attributes()->folder;
  456. $target = (string) $eFiles->attributes()->target;
  457. // Create folder path
  458. if (empty($target))
  459. {
  460. $targetFolder = JPATH_ROOT;
  461. }
  462. else
  463. {
  464. $targetFolder = JPATH_ROOT . '/' . $target;
  465. }
  466. $folderList = array();
  467. // Check if all children exists
  468. if (count($eFiles->children()) > 0)
  469. {
  470. // Loop through all filenames elements
  471. foreach ($eFiles->children() as $eFileName)
  472. {
  473. if ($eFileName->getName() == 'folder')
  474. {
  475. $folderList[] = $targetFolder . '/' . $eFileName;
  476. }
  477. else
  478. {
  479. $fileName = $targetFolder . '/' . $eFileName;
  480. JFile::delete($fileName);
  481. }
  482. }
  483. }
  484. // Delete any folders that don't have any content in them.
  485. foreach ($folderList as $folder)
  486. {
  487. $files = JFolder::files($folder);
  488. if (!count($files))
  489. {
  490. JFolder::delete($folder);
  491. }
  492. }
  493. }
  494. JFile::delete($manifestFile);
  495. // Lastly, remove the extension_root
  496. $folder = $this->parent->getPath('extension_root');
  497. if (JFolder::exists($folder))
  498. {
  499. JFolder::delete($folder);
  500. }
  501. }
  502. else
  503. {
  504. JLog::add(JText::_('JLIB_INSTALLER_ERROR_FILE_UNINSTALL_INVALID_NOTFOUND_MANIFEST'), JLog::WARNING, 'jerror');
  505. // Delete the row because its broken
  506. $row->delete();
  507. return false;
  508. }
  509. $this->parent->removeFiles($xml->languages);
  510. $row->delete();
  511. return $retval;
  512. }
  513. /**
  514. * Function used to check if extension is already installed
  515. *
  516. * @param string $extension The element name of the extension to install
  517. *
  518. * @return boolean True if extension exists
  519. *
  520. * @since 11.1
  521. */
  522. protected function extensionExistsInSystem($extension = null)
  523. {
  524. // Get a database connector object
  525. $db = $this->parent->getDBO();
  526. $query = $db->getQuery(true);
  527. $query->select($query->qn('extension_id'))
  528. ->from($query->qn('#__extensions'));
  529. $query->where($query->qn('type') . ' = ' . $query->q('file'))
  530. ->where($query->qn('element') . ' = ' . $query->q($extension));
  531. $db->setQuery($query);
  532. try
  533. {
  534. $db->execute();
  535. }
  536. catch (RuntimeException $e)
  537. {
  538. // Install failed, roll back changes
  539. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_FILE_ROLLBACK', $db->stderr(true)));
  540. return false;
  541. }
  542. $id = $db->loadResult();
  543. if (empty($id))
  544. {
  545. return false;
  546. }
  547. return true;
  548. }
  549. /**
  550. * Function used to populate files and folder list
  551. *
  552. * @return boolean none
  553. *
  554. * @since 11.1
  555. */
  556. protected function populateFilesAndFolderList()
  557. {
  558. // Initialise variable
  559. $this->folderList = array();
  560. $this->fileList = array();
  561. // Set root folder names
  562. $packagePath = $this->parent->getPath('source');
  563. $jRootPath = JPath::clean(JPATH_ROOT);
  564. // Loop through all elements and get list of files and folders
  565. foreach ($this->manifest->fileset->files as $eFiles)
  566. {
  567. // Check if the element is files element
  568. $folder = (string) $eFiles->attributes()->folder;
  569. $target = (string) $eFiles->attributes()->target;
  570. // Split folder names into array to get folder names. This will help in creating folders
  571. $arrList = preg_split("#/|\\/#", $target);
  572. $folderName = $jRootPath;
  573. foreach ($arrList as $dir)
  574. {
  575. if (empty($dir))
  576. {
  577. continue;
  578. }
  579. $folderName .= '/' . $dir;
  580. // Check if folder exists, if not then add to the array for folder creation
  581. if (!JFolder::exists($folderName))
  582. {
  583. array_push($this->folderList, $folderName);
  584. }
  585. }
  586. // Create folder path
  587. $sourceFolder = empty($folder) ? $packagePath : $packagePath . '/' . $folder;
  588. $targetFolder = empty($target) ? $jRootPath : $jRootPath . '/' . $target;
  589. // Check if source folder exists
  590. if (!JFolder::exists($sourceFolder))
  591. {
  592. JLog::add(JText::sprintf('JLIB_INSTALLER_ABORT_FILE_INSTALL_FAIL_SOURCE_DIRECTORY', $sourceFolder), JLog::WARNING, 'jerror');
  593. // If installation fails, rollback
  594. $this->parent->abort();
  595. return false;
  596. }
  597. // Check if all children exists
  598. if (count($eFiles->children()))
  599. {
  600. // Loop through all filenames elements
  601. foreach ($eFiles->children() as $eFileName)
  602. {
  603. $path['src'] = $sourceFolder . '/' . $eFileName;
  604. $path['dest'] = $targetFolder . '/' . $eFileName;
  605. $path['type'] = 'file';
  606. if ($eFileName->getName() == 'folder')
  607. {
  608. $folderName = $targetFolder . '/' . $eFileName;
  609. array_push($this->folderList, $folderName);
  610. $path['type'] = 'folder';
  611. }
  612. array_push($this->fileList, $path);
  613. }
  614. }
  615. else
  616. {
  617. $files = JFolder::files($sourceFolder);
  618. foreach ($files as $file)
  619. {
  620. $path['src'] = $sourceFolder . '/' . $file;
  621. $path['dest'] = $targetFolder . '/' . $file;
  622. array_push($this->fileList, $path);
  623. }
  624. }
  625. }
  626. }
  627. /**
  628. * Refreshes the extension table cache
  629. *
  630. * @return boolean result of operation, true if updated, false on failure
  631. *
  632. * @since 11.1
  633. */
  634. public function refreshManifestCache()
  635. {
  636. // Need to find to find where the XML file is since we don't store this normally
  637. $manifestPath = JPATH_MANIFESTS . '/files/' . $this->parent->extension->element . '.xml';
  638. $this->parent->manifest = $this->parent->isManifest($manifestPath);
  639. $this->parent->setPath('manifest', $manifestPath);
  640. $manifest_details = JInstaller::parseXMLInstallFile($this->parent->getPath('manifest'));
  641. $this->parent->extension->manifest_cache = json_encode($manifest_details);
  642. $this->parent->extension->name = $manifest_details['name'];
  643. try
  644. {
  645. return $this->parent->extension->store();
  646. }
  647. catch (RuntimeException $e)
  648. {
  649. JLog::add(JText::_('JLIB_INSTALLER_ERROR_PACK_REFRESH_MANIFEST_CACHE'), JLog::WARNING, 'jerror');
  650. return false;
  651. }
  652. }
  653. }