/**
  * Rebuilds the master 0 skin from the PHP files in /cache/{master_skin_dir}/
  *
  * @access 	public
  * @param	int			Set ID to rebuild from
  * @return	array 		Array of messages
  * <code>
  * Exception Codes:
  * NOT_MASTER_SKIN:	Set ID is not linked to a master skin directory
  * NO_SUCH_DIR:		{master_skin_dir} directory cannot be found
  * CANNOT_READ:		cannot read the {master_skin_dir} directory
  * </code>
  */
 public function rebuildMasterFromPHP($setId = 0)
 {
     //-----------------------------------------
     // INIT
     //-----------------------------------------
     $setId = is_numeric($setId) ? intval($setId) : trim($setId);
     $script_token = 0;
     $script_jump = 0;
     $skin_dir = IPS_CACHE_PATH . "cache/skin_cache/" . $this->remapData['templates'][$setId];
     $flag = 0;
     $messages = array();
     $templates = array();
     /* Got the master skin dir? */
     if (!$this->remapData['templates'][$setId]) {
         throw new Exception("NOT_MASTER_SKIN");
     }
     if (!is_dir($skin_dir)) {
         throw new Exception("NO_SUCH_DIR");
     }
     if (!is_readable($skin_dir)) {
         throw new Exception("CANNOT_READ");
     }
     /* Remove current templates... */
     if (is_numeric($setId)) {
         $this->DB->delete('skin_templates', 'template_set_id=' . $setId);
     } else {
         $this->DB->delete('skin_templates', 'template_master_key=\'' . $setId . '\'');
     }
     /* Fetch all template bits. NOW */
     if (is_numeric($setId) and $setId > 0) {
         $templates = $this->fetchTemplates($setId, 'allTemplates');
     }
     //-----------------------------------------
     // Set key and ID
     //-----------------------------------------
     $set_id = is_numeric($setId) ? $setId : $this->fetchSetIdByKey($setId);
     $set_key = '';
     if ($this->isMasterSet($setId)) {
         $set_key = is_numeric($setId) ? $this->fetchSetKeyById($setId) : $setId;
     }
     /* Loop through the directory */
     try {
         foreach (new DirectoryIterator($skin_dir) as $file) {
             if (!$file->isDot() and !$file->isDir()) {
                 $_name = $file->getFileName();
                 if (substr($_name, -4) == '.php') {
                     $name = substr($_name, 0, -4);
                     $fdata = @file_get_contents($skin_dir . "/" . $_name);
                     if (!$fdata) {
                         $messages[] = sprintf($this->lang->words['couldnotopenfile'], $_name);
                         continue;
                     }
                     $fdata = str_replace("\r", "\n", $fdata);
                     $fdata = str_replace("\n\n", "\n", $fdata);
                     if (!preg_match("/\n/", $fdata)) {
                         $messages[] = sprintf($this->lang->words['couldnotfindlineeol'], $_name);
                         continue;
                     }
                     $farray = explode("\n", $fdata);
                     $functions = array();
                     $added = 0;
                     $updated = 0;
                     foreach ($farray as $f) {
                         //-----------------------------------------
                         // Skip javascript functions...
                         //-----------------------------------------
                         if (stristr($f, '<script')) {
                             $script_token = 1;
                             $script_jump = 0;
                         }
                         if (stristr($f, '</script>')) {
                             $script_token = 0;
                             $script_jump = 0;
                         }
                         //-----------------------------------------
                         // If, in the middle?
                         //-----------------------------------------
                         if ($script_token and $script_jump == 0) {
                             if (preg_match('#<if test=[\'\\"]#', $f)) {
                                 $script_jump = 1;
                                 $script_token = 0;
                             }
                         }
                         if ($script_token == 0 and $script_jump == 1) {
                             if (preg_match("#</if>#", $f)) {
                                 $script_jump = 0;
                                 $script_token = 1;
                             }
                         }
                         //-----------------------------------------
                         // NOT IN JS
                         //-----------------------------------------
                         if (!$script_token) {
                             if (preg_match('/^function\\s*([\\w\\_]+)\\s*\\((.*)\\)/i', $f, $matches)) {
                                 $functions[$matches[1]] = '';
                                 $config[$matches[1]] = $matches[2];
                                 $flag = $matches[1];
                                 continue;
                             }
                         } else {
                             # Make JS safe (UBE - Ugly, but effective)
                             $f = preg_replace('#if\\s+?\\(#is', "i~f~(~", $f);
                             $f = str_ireplace('else', "e~lse~", $f);
                             $f = preg_replace('#else\\s+?if#is', "e~lse~i~f", $f);
                         }
                         if ($flag) {
                             $functions[$flag] .= $f . "\n";
                             continue;
                         }
                     }
                     $final = "";
                     $flag = 0;
                     foreach ($functions as $fname => $ftext) {
                         preg_match("#//--starthtml--//(.+?)//--endhtml--//#s", $ftext, $matches);
                         $content = $this->registry->templateEngine->convertPhpToHtml($matches[1]);
                         //-----------------------------------------
                         // Unconvert JS
                         //-----------------------------------------
                         $content = str_replace("i~f~(~", "if (", $content);
                         $content = str_replace("e~lse~", "else", $content);
                         $content = str_replace("e~lse~i~f", "else if", $content);
                         /* Encode */
                         $content = IPSText::encodeForXml($content);
                         /* Build array */
                         $array = array('template_set_id' => $set_id, 'template_group' => $name, 'template_content' => $content, 'template_name' => $fname, 'template_data' => trim($config[$fname]), 'template_updated' => time(), 'template_removable' => (is_numeric($setId) and $setId) ? 1 : 0, 'template_master_key' => $set_key, 'template_added_to' => $set_id);
                         if (!$setId) {
                             $added++;
                             /* All new bits go to 'master' skin */
                             $array['template_set_id'] = 0;
                             $array['template_added_to'] = 0;
                             $array['template_master_key'] = 'root';
                             $this->DB->insert('skin_templates', $array);
                         } else {
                             /* Compare for changes? */
                             if (IPSText::contentToMd5($templates[$name][strtolower($fname)]['template_content']) != IPSText::contentToMd5($content)) {
                                 /* It's changed, so update. We create a new row as it might be inherited */
                                 $updated++;
                                 $this->DB->insert('skin_templates', $array);
                             }
                         }
                     }
                     $messages[] = sprintf($this->lang->words['tplbitimported'], $name, $added, $updated);
                     $functions = array();
                 }
             }
         }
     } catch (Exception $e) {
     }
     /* Recache */
     if (is_numeric($setId) and $setId) {
         $this->rebuildPHPTemplates($setId);
         $this->removeDeadPHPCaches($setId);
         $this->cache->putWithCacheLib('Skin_Store_' . $setId, array(), 1);
     }
     if ($set_key == 'mobile') {
         $this->rebuildMobileSkinUserAgentsFromSetDataXml();
     }
     /* Return */
     $messages[] = $this->lang->words['cpltrebuildfromcaches'];
     return $messages;
 }
 /**
  * Builds the language db entries from cache
  *
  * @param	boolean			return as normal
  * @return	@e void
  * @author	Josh
  */
 public function importFromCacheFiles($returnAsNormal = TRUE)
 {
     //-----------------------------------------
     // INIT
     //-----------------------------------------
     $msg = array();
     $lang_id = 1;
     $LATESTVERSION = IPSLib::fetchVersionNumber();
     //-----------------------------------------
     // Check
     //-----------------------------------------
     if (!is_array($_POST['apps'])) {
         $this->registry->output->global_message = $this->lang->words['l_noapp'];
         $this->languagesList();
         return;
     }
     //-----------------------------------------
     // Loop through apps...
     //-----------------------------------------
     foreach (ipsRegistry::$applications as $app => $app_data) {
         if (in_array($app, $_POST['apps'])) {
             //-----------------------------------------
             // Get directory
             //-----------------------------------------
             $_dir = IPS_CACHE_PATH . 'cache/lang_cache/master_lang/';
             //-----------------------------------------
             // Go through directories
             //-----------------------------------------
             if (is_dir($_dir)) {
                 $dh = opendir($_dir);
                 while ($f = readdir($dh)) {
                     if ($f[0] == '.' || $f == 'index.html') {
                         continue;
                     }
                     if (preg_match("#^" . $app . '_\\S+?\\.php$#', $f)) {
                         //-----------------------------------------
                         // INIT
                         //-----------------------------------------
                         $updated = 0;
                         $inserted = 0;
                         $word_pack = preg_replace("#^" . $app . '_(\\S+?)\\.php$#', "\\1", $f);
                         $lang = array();
                         $db_lang = array();
                         //-----------------------------------------
                         // Delete current language bits
                         //-----------------------------------------
                         $this->DB->delete('core_sys_lang_words', "lang_id=1 AND word_app='" . $app . "' AND word_pack='" . $word_pack . "'");
                         if (IPS_IS_SHELL) {
                             $stdout = fopen('php://stdout', 'w');
                             fwrite($stdout, 'Processing: ' . $f . "\n");
                             fclose($stdout);
                         }
                         require $_dir . $f;
                         /*noLibHook*/
                         //-----------------------------------------
                         // Loop
                         //-----------------------------------------
                         foreach ($lang as $k => $v) {
                             $inserted++;
                             $insert = array('lang_id' => $lang_id, 'word_app' => $app, 'word_pack' => $word_pack, 'word_key' => $k, 'word_default' => IPSText::encodeForXml($v), 'word_default_version' => $LATESTVERSION['long'], 'word_js' => 0);
                             $this->DB->insert('core_sys_lang_words', $insert);
                         }
                         $msg[] = sprintf($this->lang->words['indev_lang_import'], $f, $inserted, $updated);
                     } else {
                         if (preg_match('/(\\.js)$/', $f) and $app == 'core') {
                             $_js_word_pack = '';
                             if ($f == 'ipb.lang.js') {
                                 $_js_word_pack = 'public_js';
                             } else {
                                 if ($f == 'acp.lang.js') {
                                     $_js_word_pack = 'admin_js';
                                 }
                             }
                             //-----------------------------------------
                             // Delete current words for this app and word pack
                             //-----------------------------------------
                             $this->DB->delete('core_sys_lang_words', "lang_id=1 AND word_app='" . $app . "' AND word_pack='" . $_js_word_pack . "'");
                             if (IPS_IS_SHELL) {
                                 $stdout = fopen('php://stdout', 'w');
                                 fwrite($stdout, 'Processing: ' . $f . "\n");
                                 fclose($stdout);
                             }
                             //-----------------------------------------
                             // Get each line
                             //-----------------------------------------
                             $js_file = file($_dir . $f);
                             //-----------------------------------------
                             // Loop through lines and import
                             //-----------------------------------------
                             foreach ($js_file as $r) {
                                 //-----------------------------------------
                                 // preg_match what we want
                                 //-----------------------------------------
                                 preg_match('#ipb\\.lang\\[\'(.+?)\'\\](.+?)= ["\'](.+?)["\'];#', $r, $matches);
                                 //-----------------------------------------
                                 // Valid?
                                 //-----------------------------------------
                                 if ($matches[1] && $matches[3]) {
                                     $inserted++;
                                     $insert = array('lang_id' => $lang_id, 'word_app' => 'core', 'word_pack' => $_js_word_pack, 'word_key' => $matches[1], 'word_default' => IPSText::encodeForXml($matches[3]), 'word_js' => 1);
                                     $this->DB->insert('core_sys_lang_words', $insert);
                                 }
                             }
                         }
                     }
                 }
                 closedir($dh);
             }
         }
     }
     //-----------------------------------------
     // Done...
     //-----------------------------------------
     if ($returnAsNormal === TRUE) {
         $this->registry->output->setMessage(implode("<br />", $msg), true);
         if (!$this->__daily) {
             $this->languagesList();
         }
     } else {
         return $msg;
     }
 }
 /**
  * Rebuilds the master 0 skin from the PHP files in /cache/{master_skin_dir}/
  *
  * @access 	public
  * @param	int			Set ID to rebuild from
  * @return	array 		Array of messages
  * <code>
  * Exception Codes:
  * NOT_MASTER_SKIN:	Set ID is not linked to a master skin directory
  * NO_SUCH_DIR:		{master_skin_dir} directory cannot be found
  * CANNOT_READ:		cannot read the {master_skin_dir} directory
  * </code>
  */
 public function rebuildMasterFromPHP($setId = 0)
 {
     //-----------------------------------------
     // INIT
     //-----------------------------------------
     $setId = intval($setId);
     $script_token = 0;
     $script_jump = 0;
     $skin_dir = IPS_CACHE_PATH . "cache/skin_cache/" . $this->remapData['templates'][$setId];
     $flag = 0;
     $messages = array();
     $templates = array();
     /* Got the master skin dir? */
     if (!$this->remapData['templates'][$setId]) {
         throw new Exception("NOT_MASTER_SKIN");
     }
     if (!file_exists($skin_dir)) {
         throw new Exception("NO_SUCH_DIR");
     }
     if (!is_readable($skin_dir)) {
         throw new Exception("CANNOT_READ");
     }
     /* Remove current templates... */
     $this->DB->delete('skin_templates', 'template_set_id=' . $setId);
     /* Fetch all template bits. NOW */
     if ($setId > 0) {
         $templates = $this->fetchTemplates($setId, 'allTemplates');
     }
     /* Loop through the directory */
     try {
         foreach (new DirectoryIterator($skin_dir) as $file) {
             if (!$file->isDot() and !$file->isDir()) {
                 $_name = $file->getFileName();
                 if (substr($_name, -4) == '.php') {
                     $name = substr($_name, 0, -4);
                     $fdata = @file_get_contents($skin_dir . "/" . $_name);
                     if (!$fdata) {
                         $messages[] = "Could not open {$_name} for reading, skipping file...";
                         continue;
                     }
                     $fdata = str_replace("\r", "\n", $fdata);
                     $fdata = str_replace("\n\n", "\n", $fdata);
                     if (!preg_match("/\n/", $fdata)) {
                         $messages[] = "Could not find any line endings in {$_name}, skipping file...";
                         continue;
                     }
                     $farray = explode("\n", $fdata);
                     $functions = array();
                     $added = 0;
                     $updated = 0;
                     foreach ($farray as $f) {
                         //-----------------------------------------
                         // Skip javascript functions...
                         //-----------------------------------------
                         if (stristr($f, '<script')) {
                             $script_token = 1;
                             $script_jump = 0;
                         }
                         if (stristr($f, '</script>')) {
                             $script_token = 0;
                             $script_jump = 0;
                         }
                         //-----------------------------------------
                         // If, in the middle?
                         //-----------------------------------------
                         if ($script_token and $script_jump == 0) {
                             if (preg_match("#<if test=[\\'\"]#", $f)) {
                                 $script_jump = 1;
                                 $script_token = 0;
                             }
                         }
                         if ($script_token == 0 and $script_jump == 1) {
                             if (preg_match("#</if>#", $f)) {
                                 $script_jump = 0;
                                 $script_token = 1;
                             }
                         }
                         //-----------------------------------------
                         // NOT IN JS
                         //-----------------------------------------
                         if (!$script_token) {
                             if (preg_match("/^function\\s*([\\w\\_]+)\\s*\\((.*)\\)/i", $f, $matches)) {
                                 $functions[$matches[1]] = '';
                                 $config[$matches[1]] = $matches[2];
                                 $flag = $matches[1];
                                 continue;
                             }
                         } else {
                             # Make JS safe (UBE - Ugly, but effective)
                             $f = preg_replace("#if\\s+?\\(#is", "i~f~(~", $f);
                             $f = str_ireplace("else", "e~lse~", $f);
                             $f = preg_replace("#else\\s+?if#is", "e~lse~i~f", $f);
                         }
                         if ($flag) {
                             $functions[$flag] .= $f . "\n";
                             continue;
                         }
                     }
                     $final = "";
                     $flag = 0;
                     foreach ($functions as $fname => $ftext) {
                         preg_match("#//--starthtml--//(.+?)//--endhtml--//#s", $ftext, $matches);
                         $content = $this->registry->templateEngine->convertPhpToHtml($matches[1]);
                         //-----------------------------------------
                         // Unconvert JS
                         //-----------------------------------------
                         $content = str_replace("i~f~(~", "if (", $content);
                         $content = str_replace("e~lse~", "else", $content);
                         $content = str_replace("e~lse~i~f", "else if", $content);
                         /* Encode */
                         $content = IPSText::encodeForXml($content);
                         /* Build array */
                         $array = array('template_set_id' => $setId, 'template_group' => $name, 'template_content' => $content, 'template_name' => $fname, 'template_data' => trim($config[$fname]), 'template_updated' => time(), 'template_removable' => $setId ? 1 : 0, 'template_added_to' => $setId);
                         if (!$setId or !$templates[$name][strtolower($fname)]) {
                             $added++;
                             /* All new bits go to 'master' skin */
                             $array['template_set_id'] = 0;
                             $array['template_added_to'] = 0;
                             $this->DB->insert('skin_templates', $array);
                         } else {
                             /* Compare for changes? */
                             if (IPSText::contentToMd5($templates[$name][strtolower($fname)]['template_content']) != IPSText::contentToMd5($content)) {
                                 /* It's changed, so update. We create a new row as it might be inherited */
                                 $updated++;
                                 $this->DB->insert('skin_templates', $array);
                             }
                         }
                     }
                     $messages[] = "{$name} imported (Added " . $added . "; updated " . $updated . " template bits)";
                     $functions = array();
                 }
             }
         }
     } catch (Exception $e) {
     }
     /* Recache */
     if ($setId) {
         $this->rebuildPHPTemplates($setId);
         $this->removeDeadPHPCaches($setId);
     }
     /* Return */
     $messages[] = "Completed database rebuild from PHP cache files.";
     return $messages;
 }