<?php /** * HTML template for the install * * @package Install * @category Helper * @author Chema <chema@open-classifieds.com> * @copyright (c) 2009-2014 Open Classifieds Team * @license GPL v3 */ ob_start(); error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE); ini_set('display_errors', 1); @set_time_limit(0); // Set the full path to the docroot define('DOCROOT', realpath(dirname(__FILE__)).DIRECTORY_SEPARATOR); //we check first short tags if not we can not even load the installer if (! ((bool) ini_get('short_open_tag')) ) die('<strong><u>OC Installation requirement</u></strong>: Before you proceed with your OC installation: Keep in mind OC uses the short tag "short cut" syntax.<br><br> Thus the <a href="http://php.net/manual/ini.core.php#ini.short-open-tag" target="_blank">short_open_tag</a> directive must be enabled in your php.ini.<br><br><u>Easy Solution</u>:<ol><li>Open php.ini file and look for line short_open_tag = Off</li><li>Replace it with short_open_tag = On</li><li>Restart then your PHP server</li><li>Refresh this page to resume your OC installation</li><li>Enjoy OC ;)</li></ol>'); //read from oc/versions.json on CDN $versions = install::versions(); $last_version = key($versions); $is_compatible = install::is_compatible(); /** * Helper installation classes * * @package Install * @category Helper * @author Chema <chema@garridodiaz.com> * @copyright (c) 2009-2014 Open Classifieds Team * @license GPL v3 */ /** * Class with install functions helper */ class install{ /** * * Software install settings * @var string */ const VERSION = '2.2.0'; /** * message to notify * @var string */ public static $msg = ''; /** * installation error messages here * @var string */ public static $error_msg = ''; /** * checks that your hosting has everything that needs to have * @return array */ public static function requirements() { /** * mod rewrite check */ if(function_exists('apache_get_modules')) { $mod_msg = 'Install requires Apache mod_rewrite module to be installed'; $mod_mandatory = TRUE; $mod_result = in_array('mod_rewrite',apache_get_modules()); } //in case they dont use apache a nicer message else { $mod_msg = 'Can not check if mod_rewrite installed, probably everything is fine. Try to proceed with the installation anyway ;)'; $mod_mandatory = FALSE; $mod_result = FALSE; } /** * all the install checks */ return array( 'Write DIR' =>array('message' => 'Can\'t write to the current directory. Please fix this by giving the webserver user write access to the directory.', 'mandatory' => TRUE, 'result' => (is_writable(DOCROOT)) ), 'PHP' =>array('message' => 'PHP 5.3 or newer is required, this version is '. PHP_VERSION, 'mandatory' => TRUE, 'result' => version_compare(PHP_VERSION, '5.3', '>=') ), 'mod_rewrite'=>array('message' => $mod_msg, 'mandatory' => $mod_mandatory, 'result' => $mod_result ), 'Short Tag' =>array('message' => '<a href="http://www.php.net/manual/en/ini.core.php#ini.short-open-tag">short_open_tag</a> must be enabled in your php.ini.', 'mandatory' => TRUE, 'result' => (bool) ini_get('short_open_tag') ), 'Safe Mode' =>array('message' => '<a href="http://php.net/manual/en/features.safe-mode.php>safe_mode</a> must be disabled.', 'mandatory' => TRUE, 'result' => ((bool) ini_get('safe_mode'))?FALSE:TRUE ), 'PCRE UTF8' =>array('message' => '<a href="http://php.net/pcre">PCRE</a> has not been compiled with UTF-8 support.', 'mandatory' => TRUE, 'result' => (bool) (@preg_match('/^.$/u', 'ñ')) ), 'PCRE Unicode'=>array('message' => '<a href="http://php.net/pcre">PCRE</a> has not been compiled with Unicode property support.', 'mandatory' => TRUE, 'result' => (bool) (@preg_match('/^\pL$/u', 'ñ')) ), 'SPL' =>array('message' => 'PHP <a href="http://www.php.net/spl">SPL</a> is either not loaded or not compiled in.', 'mandatory' => TRUE, 'result' => (function_exists('spl_autoload_register')) ), 'Reflection'=>array('message' => 'PHP <a href="http://www.php.net/reflection">reflection</a> is either not loaded or not compiled in.', 'mandatory' => TRUE, 'result' => (class_exists('ReflectionClass')) ), 'Filters' =>array('message' => 'The <a href="http://www.php.net/filter">filter</a> extension is either not loaded or not compiled in.', 'mandatory' => TRUE, 'result' => (function_exists('filter_list')) ), 'Iconv' =>array('message' => 'The <a href="http://php.net/iconv">iconv</a> extension is not loaded.', 'mandatory' => TRUE, 'result' => (extension_loaded('iconv')) ), 'Mbstring' =>array('message' => 'The <a href="http://php.net/mbstring">mbstring</a> extension is not loaded.', 'mandatory' => TRUE, 'result' => (extension_loaded('mbstring')) ), 'CType' =>array('message' => 'The <a href="http://php.net/ctype">ctype</a> extension is not enabled.', 'mandatory' => TRUE, 'result' => (function_exists('ctype_digit')) ), 'URI' =>array('message' => 'Neither <code>$_SERVER[\'REQUEST_URI\']</code>, <code>$_SERVER[\'PHP_SELF\']</code>, or <code>$_SERVER[\'PATH_INFO\']</code> is available.', 'mandatory' => TRUE, 'result' => (isset($_SERVER['REQUEST_URI']) OR isset($_SERVER['PHP_SELF']) OR isset($_SERVER['PATH_INFO'])) ), 'cUrl' =>array('message' => 'Install requires the <a href="http://php.net/curl">cURL</a> extension for the Request_Client_External class.', 'mandatory' => TRUE, 'result' => (extension_loaded('curl')) ), 'mcrypt' =>array('message' => 'Install requires the <a href="http://php.net/mcrypt">mcrypt</a> for the Encrypt class.', 'mandatory' => TRUE, 'result' => (extension_loaded('mcrypt')) ), 'GD' =>array('message' => 'Install requires the <a href="http://php.net/gd">GD</a> v2 for the Image class', 'mandatory' => TRUE, 'result' => (function_exists('gd_info')) ), 'MySQL' =>array('message' => 'Install requires the <a href="http://php.net/mysqli">MySQLi</a> extension to support MySQL databases.', 'mandatory' => TRUE, 'result' => (function_exists('mysqli_connect')) ), 'ZipArchive' =>array('message' => 'PHP module zip not installed. You will need this to auto update the software.', 'mandatory' => FALSE, 'result' => class_exists('ZipArchive') ), ); } /** * checks from requirements if its compatible or not. Also fills the msg variable * @return boolean */ public static function is_compatible() { self::$msg = ''; $compatible = TRUE; foreach (install::requirements() as $name => $values) { if ($values['mandatory'] == TRUE AND $values['result'] == FALSE) $compatible = FALSE; if ($values['result'] == FALSE) self::$msg .= $values['message'].'<br>'; } return $compatible; } /** * get phpinfo clean in a string * @return strin */ public static function phpinfo() { ob_start(); @phpinfo(); $phpinfo = ob_get_contents(); ob_end_clean(); //strip the body html return preg_replace('%^.*<body>(.*)</body>.*$%ms', '$1', $phpinfo); } /** * returns array of last versions from json * @return array */ public static function versions() { return json_decode(core::curl_get_contents('http://open-classifieds.com/files/versions.json?r='.time()),TRUE); } } class core{ /** * copies files/directories recursively * @param string $source from * @param string $dest to * @param integer $overwrite 0=do not overwrite 1=force overwrite 2=overwrite only is size is different * @return void */ public static function copy($source, $dest, $overwrite = 0) { //be sure source exists.. if (!is_readable($source)) die('File ('.$source.') could not be readed, likely a permissions problem.'); //just a file to copy, so do it! if(is_file($source)) { $copy_file = FALSE; //if doesnt exists OR we want to overwrite always OR different size copy the file. if( !is_file( $dest ) OR $overwrite == 1 OR ( $overwrite == 2 AND filesize($source)===filesize($dest) ) ) $copy_file = TRUE; if ($copy_file === TRUE) { try { copy($source, $dest); } catch (Exception $e) { die('File ('.$source.') could not be copied, likely a permissions problem.'); } } //always return if its a file, so we dont move forward return; } //was not a file, so folder...lets check exists, if not create it if(!is_dir($dest)) mkdir($dest); //read folder contents $objects = scandir($source); foreach ($objects as $object) { if($object != '.' && $object != '..') { $from = $source . '/' . $object; $to = $dest . '/' . $object; Core::copy($from, $to, $overwrite); } } } /** * recursively deletes file or directory * @param string $file * @return void */ public static function delete($file) { if (is_dir($file)) { $objects = scandir($file); foreach ($objects as $object) { if ($object != '.' AND $object != '..') { if (is_dir($file.'/'.$object)) core::delete($file.'/'.$object); //recursive else unlink($file.'/'.$object); } } reset($objects); @rmdir($file); } elseif(is_file($file)) unlink($file); } /** * gets the html content from a URL * @param string $url * @return string on success, false on errors */ public static function curl_get_contents($url) { $c = curl_init(); if ($c === FALSE) return FALSE; curl_setopt($c, CURLOPT_RETURNTRANSFER, 1); curl_setopt($c, CURLOPT_URL, $url); curl_setopt($c, CURLOPT_TIMEOUT,30); // curl_setopt($c, CURLOPT_FOLLOWLOCATION, TRUE); // $contents = curl_exec($c); $contents = core::curl_exec_follow($c); curl_close($c); return ($contents)? $contents : FALSE; } /** * [curl_exec_follow description] http://us2.php.net/manual/en/function.curl-setopt.php#102121 * @param curl $ch handler * @param integer $maxredirect hoe many redirects we allow * @return contents */ public static function curl_exec_follow($ch, $maxredirect = 5) { //using normal curl redirect if (ini_get('open_basedir') == '' AND ini_get('safe_mode' == 'Off')) { curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $maxredirect > 0); curl_setopt($ch, CURLOPT_MAXREDIRS, $maxredirect); } //using safemode...WTF! else { curl_setopt($ch, CURLOPT_FOLLOWLOCATION, FALSE); if ($maxredirect > 0) { $newurl = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); $rch = curl_copy_handle($ch); curl_setopt($rch, CURLOPT_HEADER, TRUE); curl_setopt($rch, CURLOPT_NOBODY, TRUE); curl_setopt($rch, CURLOPT_FORBID_REUSE, FALSE); curl_setopt($rch, CURLOPT_RETURNTRANSFER, TRUE); do { curl_setopt($rch, CURLOPT_URL, $newurl); $header = curl_exec($rch); if (curl_errno($rch)) $code = 0; else { $code = curl_getinfo($rch, CURLINFO_HTTP_CODE); if ($code == 301 OR $code == 302) { preg_match('/Location:(.*?)\n/', $header, $matches); $newurl = trim(array_pop($matches)); } else $code = 0; } } while ($code AND --$maxredirect); curl_close($rch); if (!$maxredirect) { if ($maxredirect === NULL) trigger_error('Too many redirects. When following redirects, libcurl hit the maximum amount.', E_USER_WARNING); else $maxredirect = 0; return FALSE; } curl_setopt($ch, CURLOPT_URL, $newurl); } } return curl_exec($ch); } /** * rss reader * @param string $url * @return array */ public static function rss($url) { $items = array(); $rss = simplexml_load_file($url); if($rss) $items = $rss->channel->item; return $items; } /** * shortcut for the query method $_GET * @param [type] $key [description] * @param [type] $default [description] * @return [type] [description] */ public static function get($key,$default=NULL) { return (isset($_GET[$key]))?$_GET[$key]:$default; } /** * shortcut for $_POST[] * @param [type] $key [description] * @param [type] $default [description] * @return [type] [description] */ public static function post($key,$default=NULL) { return (isset($_POST[$key]))?$_POST[$key]:$default; } /** * shortcut to get or post * @param [type] $key [description] * @param [type] $default [description] * @return [type] [description] */ public static function request($key,$default=NULL) { return (core::post($key)!==NULL)?core::post($key):core::get($key,$default); } } /** * gettext short cut currently @TODO just echoes untranslated string * @param [type] $msgid [description] * @return [type] [description] */ function __($msgid) { return $msgid; } ?> <!doctype html> <!--[if lt IE 7]> <html class="no-js ie6 oldie" lang="en"> <![endif]--> <!--[if IE 7]> <html class="no-js ie7 oldie" lang="en"> <![endif]--> <!--[if IE 8]> <html class="no-js ie8 oldie" lang="en"> <![endif]--> <!--[if gt IE 8]><!--> <html class="no-js" lang="en>"> <!--<![endif]--> <head> <meta charset="utf8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title>Open Classifieds <?=__("Update")?></title> <meta name="copyright" content="Open Classifieds <?=install::VERSION?>" > <meta name="author" content="Open Classifieds"> <meta name="viewport" content="width=device-width,initial-scale=1"> <link rel="shortcut icon" href="http://open-classifieds.com/wp-content/uploads/2012/04/favicon1.ico" /> <!-- Le HTML5 shim, for IE6-8 support of HTML elements --> <!--[if lt IE 9]> <script type="text/javascript" src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <style type="text/css"> body { padding-top: 60px; padding-bottom: 40px; } .sidebar-nav { padding: 9px 0; } .chosen-single{padding: 4px 0px 27px 8px!important;} .chosen-single b{margin: 4px!important;} .navbar-brand{padding: 4px 50px 0px 0px!important;} .we-install{padding: 11px!important;margin-top: 7px;} .adv{display: none;} .logo img {margin-top: 10px;} .page-header{margin: 25px 0 21px!important;} .mb-10{margin-bottom: 10px!important;} #myTab{margin-top: 14px;} </style> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootswatch/3.2.0/flatly/bootstrap.min.css"> <link rel="stylesheet" href="//cdn.jsdelivr.net/chosen/1.1.0/chosen.min.css"> </head> <body> <div class="container"> <div class="navbar navbar-fixed-top navbar-inverse"> <div class="navbar-inner"> <div class="container"> <button class="navbar-toggle pull-left" type="button" data-toggle="collapse" data-target=".bs-navbar-collapse"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <div class="navbar-collapse bs-navbar-collapse collapse"> <ul class="nav navbar-nav"> <li class="active"><a href="#home" data-toggle="tab">Install</a></li> <li><a href="http://open-classifieds.com/support/" target="_blank">Support</a></li> <li><a href="#home" data-toggle="tab">Requirements</a></li> </ul> <div class="btn-group pull-right"> <a class="btn btn-primary we-install" href="http://market.open-classifieds.com/services/one-time-support.html"> <i class="glyphicon-shopping-cart glyphicon"></i> <?=__("We can update it for you, Buy now!")?> </a> </div> </div> </div> </div> </div> <a class="logo" target="_blank" href="http://open-classifieds.com"> <img src="http://open-classifieds.com/wp-content/uploads/2012/04/OC_noTagline_286x52.png" alt="Open Classifieds <?=__("Update system")?>"> </a> <div class="tab-content"> <div class="tab-pane fade in active" id="home"> <? //choosing what to display //execute installation since they are posting data if ( $_POST AND $is_compatible === TRUE) { //theres post, download latest version, unzip and rediret to install //download file //$file_content = core::curl_get_contents($versions[$last_version]['download']); $file_content = core::curl_get_contents('http://j.mp/oc_220'); file_put_contents('oc.zip', $file_content); $zip = new ZipArchive; // open zip file, extract to dir if ($zip_open = $zip->open('oc.zip')) { if ( !($folder_update = $zip->getNameIndex(0)) ) die('Could not read the ZIP file.'); //list of files to ignore the copy $update_ignore_list = array('robots.txt', 'oc/config/auth.php', 'oc/config/database.php', '.htaccess', 'sitemap.xml.gz', 'sitemap.xml', 'images/', ); //STEP 1 extract the ZIP into the folder openclassifieds2- $zip->extractTo(DOCROOT); $zip->close(); //STEP 2 copy the ignored files from the installation to the update folder foreach ($update_ignore_list as $file) Core::copy(DOCROOT.$file,DOCROOT.$folder_update.'/'.$file,1); //STEP 3 delete default theme from docroot Core::delete(DOCROOT.'/themes/default'); //STEP 4 copy the other themes Core::copy(DOCROOT.'/themes',DOCROOT.$folder_update.'/themes',1); //STEP 5 delete the install folder from the update since we dont need it Core::delete(DOCROOT.$folder_update.'/install/'); //STEP 6 delete all the remaining old files Core::delete(DOCROOT.'/oc'); Core::delete(DOCROOT.'/languages'); Core::delete(DOCROOT.'/index.php'); //STEP 7 copy from update to the root core::copy($folder_update, DOCROOT,1); // STEP 8 delete extracted folder core::delete($folder_update); // STEP 9 and last redirect to update DB $url = 'http://'.$_SERVER['SERVER_NAME']; if ($_SERVER['SERVER_PORT'] != '80') $url = $url.':'.$_SERVER['SERVER_PORT']; //getting the folder, erasing the current $folder = str_replace('/update220.php','', $_SERVER['SCRIPT_NAME']).'/oc-panel/update/database?from_version=2.0.3'; $url .= $folder; header("Location: ".$url); exit; } else hosting_view(); } //normally if compatible just display the form elseif ($is_compatible === TRUE) {?> <?if (!empty(install::$msg) OR !empty(install::$error_msg)) hosting_view();?> <div class="page-header"> <h1>Update Open Classifieds v.2.2.0</h1> <p>We will download 2.2.0 stable version of Open Classifieds and update it for you. Please make a backup before moving forward. <br> Once you click in the install button can take few seconds until downloaded, please do not close this window.</p> <div class="clearfix"></div> </div> <form method="post" action="" class="" > <fieldset> <div class="form-action"> <input type="submit" name="action" id="submit" value="Download and Update" class="btn btn-primary btn-large" /> </div> </fieldset> </form> <?} //not compatible else hosting_view(); ?> <hr> <h3><?=__("Software Requirements")?> v.<?=$last_version;?></h3> <p><?=__('Requirements checks we do before we install.')?> <span class="label label-info" id="phpinfobutton" >phpinfo()</span> </p> <?foreach (install::requirements() as $name => $values): $color = ($values['result'])?'success':'danger';?> <div class="pull-left <?=$color?>" style=" width: 100px; height: 56px; text-align: center;"> <h4><i class="glyphicon glyphicon-<?=($values['result'])?"ok":"remove"?>"></i> <div class="clearfix"></div> <?printf ('<span class="label label-%s">%s</span>',$color,$name);?> </h4> </div> <?endforeach?> <div class="clearfix"></div><br> <div class="hidden" id="phpinfo"> <?=str_replace('<table', '<table class="table table-striped table-bordered"', install::phpinfo())?> </div> </div> </div> <hr> <footer> <p> © <a href="http://open-classifieds.com" title="Open Source PHP Classifieds">Open Classifieds</a> 2009 - <?=date('Y')?> </p> </footer> </div> <script src="http://code.jquery.com/jquery-1.11.0.min.js"></script> <script src="//netdna.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script> <script src="//cdn.jsdelivr.net/jquery.bootstrapvalidation/1.3.7/jqBootstrapValidation.min.js"></script> <script src="//cdn.jsdelivr.net/chosen/1.1.0/chosen.jquery.min.js"></script> <script> $(function () { $("select").chosen(); $("input,select,textarea").not("[type=submit]").jqBootstrapValidation(); $('input, select').tooltip(); }); $('#advanced-options').click(function(){ if($(this).hasClass('btn-primary')) { $(this).removeClass('btn-primary'); $(this).addClass('btn-default'); $('.adv').each(function(){ $(this).hide(); }); $('#myTab').css('display','none'); } else { $(this).removeClass('btn-default'); $(this).addClass('btn-primary'); $('.adv').each(function(){ $(this).show(); }); $('#myTab').css('display','block'); } }); $('#phpinfobutton').click(function(){ if($('#phpinfo').hasClass('hidden')) { $(this).removeClass('label-info'); $(this).addClass('label-warning'); $('#phpinfo').removeClass('hidden'); } else { $(this).removeClass('label-warning'); $(this).addClass('label-info'); $('#phpinfo').addClass('hidden'); } }); </script> </body> </html> <? /** * displayed in case not compatible * @return [type] [description] */ function hosting_view() { ?> <?if (!empty(install::$error_msg)):?> <br> <div class="alert alert-danger"><?=install::$error_msg?></div> <?endif?> <?if(!empty(install::$msg)):?> <br> <div class="alert alert-warning"> <?=__("We have detected some incompatibilities, update may not work as expected but you can try.")?> <br> <?=install::$msg?> </div> <?endif?> <? } ?>