public function clean() { if (!isset($this->themeInfo)) { return; } if (!isset($this->themeInfo->hash)) { return; } // don't clean if in DB because it means someone has posted the archive previously, and maybe the current user tries to erase it. if (USE_DB) { $history = new History(); $id = $history->getIdFromHash($this->themeInfo->hash); if (!empty($id)) { return; } } $zipfilepath = self::hashToPathUpload($this->themeInfo->hash); $unzippath = TC_ROOTDIR . '/../themecheck_vault/unzip/' . $this->themeInfo->hash; $unzippath_parent = TC_ROOTDIR . '/../themecheck_vault/unzip/' . $this->themeInfo->hash . '_tc_parentzip'; if (file_exists($zipfilepath)) { unlink($zipfilepath); } if (file_exists($unzippath)) { ListDirectoryFiles::recursiveRemoveDir($unzippath); } if (file_exists($unzippath_parent)) { ListDirectoryFiles::recursiveRemoveDir($unzippath_parent); } }
/** * Analyze an unzipped theme and get metadata **/ public function initFromUnzippedArchive($unzippath, $zipfilename, $zipmimetype, $zipfilesize) { $this->zipfilename = $zipfilename; $this->zipmimetype = $zipmimetype; $this->zipfilesize = $zipfilesize; $this->userIp = $_SERVER['REMOTE_ADDR']; if ($this->userIp == '::1') { $this->userIp = '127.0.0.1'; } $this->layout = 0; $rawlicense = ''; // list of meaningful files in themes // txt, csv, etc. are meaningless $filetypes = array('css' => false, 'php' => false, 'html' => false, 'phtml' => false, 'htm' => false, 'xml' => false, 'gif' => false, 'jpeg' => false, 'png' => false, 'psd' => false, 'ai' => false, 'doc' => false, 'docx' => false, 'rtf' => false); try { $files = listdir($unzippath); } catch (Exception $e) { UserMessage::enqueue(__("Cannot list files in archive."), ERRORLEVEL_FATAL); return false; } if (empty($files)) { UserMessage::enqueue(__("Cannot list files in archive."), ERRORLEVEL_FATAL); return false; } // test for nested zips $nestedzipfiles = array(); $indexphp_count = 0; foreach ($files as $key => $filename) { $path_parts = pathinfo($filename); if (isset($path_parts['extension'])) { if ($path_parts['extension'] == 'zip') { $nestedzipfiles[] = $filename; } if ($path_parts['basename'] == 'index.php') { /* $subdir = substr($path_parts['dirname'], strpos($path_parts['dirname'], '/unzip/') + 7); if (strpos($subdir,"\\")!==false || strpos($subdir,"/")!==false) { UserMessage::enqueue(__("index.php must be in root directory."), ERRORLEVEL_FATAL); return false; }*/ $indexphp_count++; } } } if (count($nestedzipfiles) > 0 && $indexphp_count == 0) { $curpath = trim($unzippath, "\\/"); if (strpos($curpath, '_tc_parentzip') !== false) { UserMessage::enqueue(__("Multiple level nested zip archives are not supported."), ERRORLEVEL_FATAL); return false; } $newpath = $curpath . '_tc_parentzip'; if (!file_exists($newpath)) { rename($curpath, $newpath); } if (!file_exists($newpath)) { UserMessage::enqueue(__("Nested zip archives are not supported."), ERRORLEVEL_FATAL); return false; } try { $zipfilepath = str_replace($curpath, $newpath, $nestedzipfiles[0]); $zip = new \ZipArchive(); $unzippath = $curpath; $res = $zip->open($zipfilepath); if ($res === TRUE) { if (file_exists($unzippath)) { ListDirectoryFiles::recursiveRemoveDir($unzippath); } // needed to avoid keeping old files that don't exist anymore in the new archive $zip->extractTo($unzippath); $zip->close(); } else { UserMessage::enqueue(__("File could not be unzipped."), ERRORLEVEL_FATAL); } } catch (Exception $e) { UserMessage::enqueue(__("Archive extraction failed. The following exception occured : ") . $e->getMessage(), ERRORLEVEL_FATAL); } return $this->initFromUnzippedArchive($unzippath, $zipfilename, $zipmimetype, $zipfilesize); // only $unzippath has changed, other values still refer to parent zip } $this->themetype = $this->detectThemetype($unzippath); $merchant = self::getMerchant($unzippath, $this); $this->isThemeForest = $merchant == 'themeforest' ? true : false; $this->isTemplateMonster = $merchant == 'templatemonster' ? true : false; $this->namedemo = ''; // undefined theme type if ($this->themetype == TT_UNDEFINED) { UserMessage::enqueue(__("Archive is not a valid theme file."), ERRORLEVEL_FATAL); return false; } if ($this->themetype == TT_WORDPRESS || $this->themetype == TT_WORDPRESS_CHILD) { $style_css = null; // loop through files to find style.css (at root level since there can be other style.css files in subdirs) foreach ($files as $key => $filename) { $path_parts = pathinfo($filename); $basename = $path_parts['basename']; if ($basename == 'style.css') { if (empty($style_css)) { $style_css = $filename; $this->themeroot = realpath($path_parts['dirname']); $explod = explode(DIRECTORY_SEPARATOR, $this->themeroot); if (count($explod) > 0) { $this->namedemo = $explod[count($explod) - 1]; } } else { if (strlen($filename) < strlen($style_css)) { $style_css = $filename; $this->themeroot = realpath($path_parts['dirname']); $explod = explode(DIRECTORY_SEPARATOR, $this->themeroot); if (count($explod) > 0) { $this->namedemo = $explod[count($explod) - 1]; } } } } if (isset($path_parts['extension'])) { $ext = strtolower(trim($path_parts['extension'])); if (isset($filetypes[$ext])) { $filetypes[$ext] = true; } } } if (empty($style_css)) { UserMessage::enqueue(__("style.css is missing or misspelled."), ERRORLEVEL_FATAL); return false; } else { $file_content = file_get_contents($style_css); if (preg_match('/[ \\t\\/*#]*Theme Name:(.*)$/mi', $file_content, $match) && !empty($match) && count($match) == 2) { $this->name = trim($match[1]); } else { UserMessage::enqueue(__("style.css does not contain Theme name. Theme name is mandatory."), ERRORLEVEL_FATAL); return false; } if (preg_match('/[ \\t\\/*#]*Description:(.*)$/mi', $file_content, $match) && !empty($match) && count($match) == 2) { $this->descriptionBB = trim(strip_tags(Helpers::encodeBB($match[1]))); $this->description = Helpers::decodeBB($this->descriptionBB); } if (preg_match('/[ \\t\\/*#]*Author:(.*)$/mi', $file_content, $match) && !empty($match) && count($match) == 2) { $this->author = trim($match[1]); } if (preg_match('/[ \\t\\/*#]*Theme URI:(.*)$/mi', $file_content, $match) && !empty($match) && count($match) == 2) { $this->themeUri = trim($match[1]); } if (preg_match('/[ \\t\\/*#]*Author URI:(.*)$/mi', $file_content, $match) && !empty($match) && count($match) == 2) { $this->authorUri = trim($match[1]); } if (preg_match('/[ \\t\\/*#]*Version:(.*)$/mi', $file_content, $match) && !empty($match) && count($match) == 2) { $this->version = trim($match[1]); } if (preg_match('/[ \\t\\/*#]*License:(.*)$/mi', $file_content, $match) && !empty($match) && count($match) == 2) { $rawlicense = trim($match[1]); } if (preg_match('%[ \\t\\/*#]*License URI:.*(https?://[A-Za-z0-9-\\./_~:?#@!$&\'()*+,;=]*)%mi', $file_content, $match) && !empty($match) && count($match) == 2) { $this->licenseUri = trim($match[1]); } if (preg_match('/[ \\t\\/*#]*Tags:(.*)$/mi', $file_content, $match) && !empty($match) && count($match) == 2) { $this->tags = trim($match[1]); // layout if (strpos($this->tags, 'fixed-layout') !== false) { $this->layout = 1; } if (strpos($this->tags, 'fluid-layout') !== false) { $this->layout = 2; } if (strpos($this->tags, 'responsive-layout') !== false) { $this->layout = 3; } } if ($this->themetype == TT_WORDPRESS_CHILD && preg_match('/[ \\t\\/*#]*Template:(.*)$/mi', $file_content, $match) && !empty($match) && count($match) == 2) { $this->parentName = trim($match[1]); } // creation date can come from an external source. Happens with massimport where creation date is in csv files. global $g_creationDate; $this->creationDate = $g_creationDate; } $this->cmsVersion = "3.9.1"; } if ($this->themetype == TT_JOOMLA) { foreach ($files as $key => $filename) { $path_parts = pathinfo($filename); $basename = $path_parts['basename']; if ($basename == 'templateDetails.xml') { libxml_use_internal_errors(true); $xml = simplexml_load_file($filename); if (count(libxml_get_errors()) > 0) { foreach (libxml_get_errors() as $error) { $message = __("Malformed xml file templateDetails.xml. Cannot continue. Error details : "); $message .= $error->message; UserMessage::enqueue($message, ERRORLEVEL_FATAL); } return false; libxml_clear_errors(); } if (empty($xml)) { UserMessage::enqueue(__("templateDetails.xml is empty or contains malformed xml"), ERRORLEVEL_FATAL); return false; } if ($xml->getName() == 'extension' || $xml->getName() == 'install' || $xml->getName() == 'mosinstall') { if (!empty($xml->name)) { $this->name = (string) $xml->name; } else { UserMessage::enqueue(__("templateDetails.xml does not have a name tag. name is mandatory."), ERRORLEVEL_FATAL); return false; } if (!empty($xml->description)) { $this->descriptionBB = trim(strip_tags(Helpers::encodeBB((string) $xml->description))); $this->description = Helpers::decodeBB($this->descriptionBB); } if (!empty($xml->author)) { $this->author = (string) $xml->author; } if (!empty($xml->authorUrl)) { $this->authorUri = (string) $xml->authorUri; } if (!empty($xml->authorMail)) { $this->authorUri = (string) $xml->authorMail; } if (!empty($xml->version)) { $this->version = (string) $xml->version; } if (!empty($xml->copyright)) { $this->copyright = (string) $xml->copyright; } if (!empty($xml->creationDate)) { $this->creationDate = strtotime((string) $xml->creationDate); } if (empty($this->creationDate)) { // creation date can come from an external source. Happens with massimport where creation date is in csv files. global $g_creationDate; $this->creationDate = $g_creationDate; } if (!empty($xml->license)) { $rawlicense = (string) $xml->license; } if ($xml->getName() == 'extension') { $attrs = $xml->attributes(); if (isset($attrs["version"])) { $this->cmsVersion = (string) $attrs["version"]; } else { $this->cmsVersion = "3.0+"; } } if ($xml->getName() == 'install') { $attrs = $xml->attributes(); if (isset($attrs["version"])) { $this->cmsVersion = (string) $attrs["version"]; } else { $this->cmsVersion = "1.5"; } } if ($xml->getName() == 'mosinstall') { $this->cmsVersion = "1.0"; } // layout if (!empty($this->description)) { if (stripos($this->description, 'fluid') !== false) { $this->layout = 2; } if (stripos($this->description, 'responsive') !== false) { $this->layout = 3; } } } else { UserMessage::enqueue(__("templateDetails.xml does not have a mosinstall, extension or install or node"), ERRORLEVEL_FATAL); return false; } $this->themeroot = realpath($path_parts['dirname']); } if (isset($path_parts['extension'])) { $ext = strtolower(trim($path_parts['extension'])); if (isset($filetypes[$ext])) { $filetypes[$ext] = true; } } } if (empty($this->name)) { UserMessage::enqueue(___("templateDetails.xml is emissing or misspelled."), ERRORLEVEL_FATAL); return false; } // for joomla, extract namedemo from zip name $zipfilename_exploded = explode('.', $this->zipfilename); array_pop($zipfilename_exploded); $this->namedemo = implode('.', $zipfilename_exploded); } $this->modificationDate = time(); $this->validationDate = time(); $this->license = self::getLicense($rawlicense); if (preg_match('%(https?://[A-Za-z0-9-\\./_~:?#@!$&\'()*+,;=])%i', $rawlicense, $match) && !empty($match) && count($match) == 2) { $this->licenseUri = trim($match[1]); } if (empty($this->licenseUri)) { $this->licenseUri = self::getLicenseUri($this->license); } if ($this->license == TC_LICENSE_CUSTOM) { $this->licenseText = $rawlicense; } $this->hasBacklinKey = false; if ($filetypes['css']) { $this->filesIncluded .= 'CSS, '; } if ($filetypes['php']) { $this->filesIncluded .= 'PHP, '; } if ($filetypes['html'] || $filetypes['phtml'] || $filetypes['htm']) { $this->filesIncluded .= 'HTML, '; } if ($filetypes['xml']) { $this->filesIncluded .= 'XML, '; } if ($filetypes['gif'] || $filetypes['jpeg'] || $filetypes['png']) { $this->filesIncluded .= 'Bitmap images, '; } if ($filetypes['psd']) { $this->filesIncluded .= 'Adobe Photoshop, '; } if ($filetypes['xml']) { $this->filesIncluded .= 'Adobe Illustrator, '; } if ($filetypes['doc'] || $filetypes['docx']) { $this->filesIncluded .= 'MS Word, '; } if ($filetypes['rtf']) { $this->filesIncluded .= 'RTF, '; } $this->filesIncluded = trim($this->filesIncluded, " ,"); // get themeforest url if ($this->isThemeForest) { preg_match('/[ 0-9a-zA-Z_-]+/', $this->name, $matches, PREG_OFFSET_CAPTURE); $search = trim($matches[0][0]); $url = 'http://marketplace.envato.com/api/edge/search:themeforest,wordpress,' . $search . '.json'; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $result = curl_exec($ch); curl_close($ch); $result = json_decode($result); if (!empty($result) && !empty($result->search)) { $this->themeUri = $result->search[0]->url; } } return true; }