I have a PHP script that synchronize a local directory with a remote one ...
[...]
$ftp = new Ftp('11.222.11.222', 'the_user', 'the_pass');
$ftp->syncFolder('userfiles/project', '/web/userfiles/project', true);
[...]
And a Class
class Ftp
{
public $conn;
private $url;
private $user;
private $password;
private $loged;
/**
* Ftp constructor.
* #param $url
* #param $user
* #param $password
* #throws Exception
*/
public function __construct($url, $user, $password)
{
$this->conn = ftp_connect($url);
$this->user = $user;
$this->password = $password;
if ($this->ftp_login($this->user, $this->password)) {
$this->loged = true;
} else {
$this->loged = false;
}
$this->ftp_pasv(true);
}
/**
* #param $func
* #param $a
* #return mixed
* #throws Exception
*/
public function __call($func, $a)
{
if (strstr($func, 'ftp_') !== false && function_exists($func)) {
array_unshift($a, $this->conn);
return call_user_func_array($func, $a);
} else {
if (method_exists($this, $func)) {
return call_user_func_array($func, $a);
} else {
throw new Exception('Undefine Class Function');
}
}
}
/**
* #param $local
* #param $server
* #param $verbose
* #return bool
* #throws Exception
*/
function syncFolder($local, $server, $verbose)
{
if (!$this->loged) {
return false;
}
$this->ftp_chdir($server);
$server_list = $this->ftp_nlist('.');
$local_list = scandir(BASE_PATH . $local);
foreach ($server_list as $item) {
if ($item == '.' || $item == '..') {
continue;
}
$folder = $this->ftp_nlist($item);
if ($folder[0] == '.') {
if (!in_array($item, $local_list)) {
$this->emptyDir($server . '/' . $item, $verbose);
$this->ftp_chdir($server);
} else {
$this->syncFolder($local . '/' . $item, $server . '/' . $item, $verbose);
$this->ftp_chdir($server);
}
} else {
if (!in_array($item, $local_list)) {
if ($this->ftp_delete($item)) {
} else {
}
} else {
$stats = stat(BASE_PATH . $local . '/' . $item);
if ($this->ftp_mdtm($item) < $stats['mtime']) {
if ($this->ftp_put($item, BASE_PATH . $local . '/' . $item, FTP_BINARY)) {
} else {
}
} else {
}
}
}
}
$this->putMissingFilesFromDir($local, $server, $verbose);
$this->ftp_chdir($server);
}
/**
* #param $dir
* #param $verbose
* #return bool
* #throws Exception
*/
function emptyDir($dir, $verbose)
{
if (!$this->loged) {
return false;
}
$this->ftp_chdir($dir);
$server_list = $this->ftp_nlist('.');
foreach ($server_list as $item) {
if ($item == '.' || $item == '..') {
continue;
}
$folder = $this->ftp_nlist($item);
if ($folder[0] == '.') {
$this->emptyDir($dir . '/' . $item, $verbose);
$this->ftp_chdir($dir);
} else {
if ($this->ftp_delete($item)) {
} else {
}
}
}
if ($this->ftp_rmdir($dir)) {
} else {
}
}
/**
* #param $local
* #param $server
* #param $verbose
* #return bool
* #throws Exception
*/
function putMissingFilesFromDir($local, $server, $verbose)
{
if (!$this->loged) {
return false;
}
$this->ftp_chdir($server);
$server_list = $this->ftp_nlist('.');
$local_list = scandir(BASE_PATH . $local);
foreach ($local_list as $item) {
if ($item == '.' || $item == '..') {
continue;
}
if (is_dir(BASE_PATH . $local . '/' . $item)) {
if (!in_array($item, $server_list)) {
$this->ftp_mkdir($item);
}
$this->putMissingFilesFromDir($local . '/' . $item, $server . '/' . $item, $verbose);
$this->ftp_chdir($server);
} else {
if (!in_array($item, $server_list)) {
if ($this->ftp_put($item, BASE_PATH . $local . '/' . $item, FTP_BINARY)) {
} else {
}
}
}
}
}
}
This script works fine from browser and from windows' CMD using this command:
C:\php5.6\php.exe -f "D:\www\project\cron\synchro_hosting.php"
But when I try to run this script from a batch file in a scheduled task the ftp_connect function doesn't do anything. It remains waiting for something.
cd /D "D:\www\project\cron\"
"C:\php5.6\php.exe" -f synchro_hosting.php
I'm using a log file to write events (now removed for summarize the code) and the code stop in ftp_connect.
Ideas?
UPDATE 1:
I tried to run the same command from CMD, batch file triggered from CMD and a batch file triggered from scheduled task, and works fine with two first options. The execution stops in ftp_connect function when is triggered from batch file in a scheduled task. The windows user that execute this actions is the same in the three cases.
C:\php5.6\php.exe -f "D:\www\project\cron\synchro_hosting.php"
I don't know where is the problem with ftp_connect from scheduled task. Is maybe a permissions issue?
There are another way in Windows to trigger an php script recurrently?
As I told to Rockstar, I have found a solution to avoid the problem, not to fix it. I tried to execute a php file directly from scheduled tasks and it worked instead of execute a bat file.
The action tab from scheduled tasks should look like this:
Action: Start a program
Program or Script: C:\php5.6\php.exe
Add arguments: "D:\www\project\cron\synchro_hosting.php"
Action Tab from Scheduled Tasks
Related
I am facing an issue while doing index on SSH error:
indexer.php
<?php
/**
* Magento
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license#magento.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade Magento to newer
* versions in the future. If you wish to customize Magento for your
* needs please refer to http://www.magento.com for more information.
*
* #category Mage
* #package Mage_Shell
* #copyright Copyright (c) 2006-2015 X.commerce, Inc. (http://www.magento.com)
* #license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
*/
require_once 'abstract.php';
/**
* Magento Compiler Shell Script
*
* #category Mage
* #package Mage_Shell
* #author Magento Core Team <core#magentocommerce.com>
*/
class Mage_Shell_Compiler extends Mage_Shell_Abstract
{
/**
* Get Indexer instance
*
* #return Mage_Index_Model_Indexer
*/
protected function _getIndexer()
{
return $this->_factory->getSingleton($this->_factory->getIndexClassAlias());
}
/**
* Parse string with indexers and return array of indexer instances
*
* #param string $string
* #return array
*/
protected function _parseIndexerString($string)
{
$processes = array();
if ($string == 'all') {
$collection = $this->_getIndexer()->getProcessesCollection();
foreach ($collection as $process) {
if ($process->getIndexer()->isVisible() === false) {
continue;
}
$processes[] = $process;
}
} else if (!empty($string)) {
$codes = explode(',', $string);
$codes = array_map('trim', $codes);
$processes = $this->_getIndexer()->getProcessesCollectionByCodes($codes);
foreach($processes as $key => $process) {
if ($process->getIndexer()->getVisibility() === false) {
unset($processes[$key]);
}
}
if ($this->_getIndexer()->hasErrors()) {
echo implode(PHP_EOL, $this->_getIndexer()->getErrors()), PHP_EOL;
}
}
return $processes;
}
/**
* Run script
*
*/
public function run()
{
$_SESSION = array();
if ($this->getArg('info')) {
$processes = $this->_parseIndexerString('all');
foreach ($processes as $process) {
/* #var $process Mage_Index_Model_Process */
echo sprintf('%-30s', $process->getIndexerCode());
echo $process->getIndexer()->getName() . "\n";
}
} else if ($this->getArg('status') || $this->getArg('mode')) {
if ($this->getArg('status')) {
$processes = $this->_parseIndexerString($this->getArg('status'));
} else {
$processes = $this->_parseIndexerString($this->getArg('mode'));
}
foreach ($processes as $process) {
/* #var $process Mage_Index_Model_Process */
$status = 'unknown';
if ($this->getArg('status')) {
switch ($process->getStatus()) {
case Mage_Index_Model_Process::STATUS_PENDING:
$status = 'Pending';
break;
case Mage_Index_Model_Process::STATUS_REQUIRE_REINDEX:
$status = 'Require Reindex';
break;
case Mage_Index_Model_Process::STATUS_RUNNING:
$status = 'Running';
break;
default:
$status = 'Ready';
break;
}
} else {
switch ($process->getMode()) {
case Mage_Index_Model_Process::MODE_SCHEDULE:
$status = 'Update by schedule';
break;
case Mage_Index_Model_Process::MODE_REAL_TIME:
$status = 'Update on Save';
break;
case Mage_Index_Model_Process::MODE_MANUAL:
$status = 'Manual Update';
break;
}
}
echo sprintf('%-35s ', $process->getIndexer()->getName() . ':') . $status ."\n";
}
} else if ($this->getArg('mode-realtime') || $this->getArg('mode-manual')) {
if ($this->getArg('mode-realtime')) {
$mode = Mage_Index_Model_Process::MODE_REAL_TIME;
$processes = $this->_parseIndexerString($this->getArg('mode-realtime'));
} else {
$mode = Mage_Index_Model_Process::MODE_MANUAL;
$processes = $this->_parseIndexerString($this->getArg('mode-manual'));
}
foreach ($processes as $process) {
/* #var $process Mage_Index_Model_Process */
try {
$process->setMode($mode)->save();
echo $process->getIndexer()->getName() . " index was successfully changed index mode\n";
} catch (Mage_Core_Exception $e) {
echo $e->getMessage() . "\n";
} catch (Exception $e) {
echo $process->getIndexer()->getName() . " index process unknown error:\n";
echo $e . "\n";
}
}
} else if ($this->getArg('reindex') || $this->getArg('reindexall')) {
if ($this->getArg('reindex')) {
$processes = $this->_parseIndexerString($this->getArg('reindex'));
} else {
$processes = $this->_parseIndexerString('all');
}
try {
Mage::dispatchEvent('shell_reindex_init_process');
foreach ($processes as $process) {
/* #var $process Mage_Index_Model_Process */
try {
$startTime = microtime(true);
$process->reindexEverything();
$resultTime = microtime(true) - $startTime;
Mage::dispatchEvent($process->getIndexerCode() . '_shell_reindex_after');
echo $process->getIndexer()->getName()
. " index was rebuilt successfully in " . gmdate('H:i:s', $resultTime) . "\n";
} catch (Mage_Core_Exception $e) {
echo $e->getMessage() . "\n";
} catch (Exception $e) {
echo $process->getIndexer()->getName() . " index process unknown error:\n";
echo $e . "\n";
}
}
Mage::dispatchEvent('shell_reindex_finalize_process');
} catch (Exception $e) {
Mage::dispatchEvent('shell_reindex_finalize_process');
echo $e->getMessage() . "\n";
}
} else {
echo $this->usageHelp();
}
}
/**
* Retrieve Usage Help Message
*
*/
public function usageHelp()
{
return <<<USAGE
Usage: php -f indexer.php -- [options]
--status <indexer> Show Indexer(s) Status
--mode <indexer> Show Indexer(s) Index Mode
--mode-realtime <indexer> Set index mode type "Update on Save"
--mode-manual <indexer> Set index mode type "Manual Update"
--reindex <indexer> Reindex Data
info Show allowed indexers
reindexall Reindex Data by all indexers
help This help
<indexer> Comma separated indexer codes or value "all" for all indexers
USAGE;
}
}
$shell = new Mage_Shell_Compiler();
$shell->run();
PHP Fatal error: Call to a member function getProcessesCollection() on boolean in /chroot/home/ocztecco/ocztec.com/html/shell/indexer.php on line 58
please help me to handle this error and accomplish the indexing task. Thanks in advance.
Just integrated Google Recaptcha. I am using this form as a POST to a secure checkout for a secure transaction site ( API ).
My challenge is, I have the form action =
"action="https://securepayments.cardconnect.com/hpp/payment/"
And event if I use :
if (isset($_POST['submit'])) {
to validate the :: recaptcha :: it still just goes straight to the form action URL without verifying the recaptcha.
Here is more code:
$secret = '-- XX --';
$response = $_POST['g-recaptcha-response'];
$remoteip = $_SERVER['REMOTE_ADDR'];
$url = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=$secret&response=$response&remoteip=$remoteip");
$res = json_decode($unpass, TRUE);
$result = json_decode($url, TRUE);
if ($result['success'] == 1) {
echo $_POST['name'];
echo $_POST['companyname'];
}
else { echo 'you are a robot'; }
}
The form action URL passes POST / hidden variables to connect via MID/Password to authenticate itself with the API. I can't figure out how to integrate a solution to use recaptcha and then do the form action. Any help would be awesome!
function isValid()
{
try {
$url = 'https://www.google.com/recaptcha/api/siteverify';
$data = ['secret' => 'secret',
'response' => $_POST['g-recaptcha-response'],
'remoteip' => $_SERVER['REMOTE_ADDR']];
$options = [
'http' => [
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data)
]
];
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
return json_decode($result)->success;
}
catch (Exception $e) {
return null;
}
}
if($_POST && isValid())
{
//do stuff
}
Why you don't use the Recaptcha Library?
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
class Recaptcha
{
/*
* This is a PHP library that handles calling reCAPTCHA.
* - Documentation and latest version
* http://recaptcha.net/plugins/php/
* - Get a reCAPTCHA API Key
* https://www.google.com/recaptcha/admin/create
* - Discussion group
* http://groups.google.com/group/recaptcha
*
* Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net
* AUTHORS:
* Mike Crawford
* Ben Maurer
*
* CONTRIBUTION:
* Codeigniter version - 23.08.2012 by Christer Nordbø, Norway.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*
* UPDATE HISTORY:
* 28.08.2013 - Made recaptcha_check_answer() function bit simpler on default
* fields as html is generated by recaptcha_get_html() function.
* Updated by - Puneet Kalra (https://github.com/puneetkay)
*/
/**
* The reCAPTCHA server URL's
*/
const RECAPTCHA_API_SERVER = "http://www.google.com/recaptcha/api";
const RECAPTCHA_API_SECURE_SERVER = "https://www.google.com/recaptcha/api";
const RECAPTCHA_VERIFY_SERVER = "www.google.com";
protected $is_valid;
protected $error;
//Remember to obtain the Public and Private key # https://www.google.com/recaptcha/admin/create
protected $public_key = "YOUR PUBLIC KEY";
protected $privkey = "YOUR PRIVATE KEY";
protected $options = array();
function __construct()
{
log_message('debug', "RECAPTCHA Class Initialized.");
$this->_ci =& get_instance();
//Load the CI Config file for recaptcha
$this->_ci->load->config('recaptcha');
//load in the values from the config file.
$this->public_key = $this->_ci->config->item('public_key');
$this->privkey = $this->_ci->config->item('private_key');
$this->options = $this->_ci->config->item('recaptcha_options');
//Lets do some basic error handling to see if the configuration is A-OK.
$temp_error_msg = '';
if ($this->public_key === 'YOUR PUBLIC KEY') {
$temp_error_msg .= 'You need to set your public key in the config file <br />';
}
if ($this->privkey === 'YOUR PRIVATE KEY') {
$temp_error_msg .= 'You need to set your private key in the config file <br />';
}
if ($temp_error_msg != '') {
show_error($temp_error_msg);
}
}
/**
* Encodes the given data into a query string format
* #param $data - array of string elements to be encoded
* #return string - encoded request
*/
function recaptcha_qsencode($data)
{
$req = "";
foreach ($data as $key => $value)
$req .= $key . '=' . urlencode(stripslashes($value)) . '&';
// Cut the last '&'
$req = substr($req, 0, strlen($req) - 1);
return $req;
}
/**
* Submits an HTTP POST to a reCAPTCHA server
* #param string $host
* #param string $path
* #param array $data
* #param int port
* #return array response
*/
function recaptcha_http_post($host, $path, $data, $port = 80)
{
$req = $this->recaptcha_qsencode($data);
$http_request = "POST $path HTTP/1.0\r\n";
$http_request .= "Host: $host\r\n";
$http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
$http_request .= "Content-Length: " . strlen($req) . "\r\n";
$http_request .= "User-Agent: reCAPTCHA/PHP\r\n";
$http_request .= "\r\n";
$http_request .= $req;
$response = '';
if (false == ($fs = #fsockopen($host, $port, $errno, $errstr, 10))) {
die ('Could not open socket');
}
fwrite($fs, $http_request);
while (!feof($fs))
$response .= fgets($fs, 1160); // One TCP-IP packet
fclose($fs);
$response = explode("\r\n\r\n", $response, 2);
return $response;
}
function recaptcha_get_html($error = null, $use_ssl = false)
{
if ($this->public_key == null || $this->public_key == '') {
die ("To use reCAPTCHA you must get an API key from <a href='https://www.google.com/recaptcha/admin/create'>https://www.google.com/recaptcha/admin/create</a>");
}
if ($use_ssl) {
$server = self::RECAPTCHA_API_SECURE_SERVER;
} else {
$server = self::RECAPTCHA_API_SERVER;
}
$errorpart = "";
if ($error) {
$errorpart = "&error=" . $error;
}
$options = "";
foreach ($this->options as $key => $value) {
$options .= $key . ':"' . $value . '", ';
}
return '<script type="text/javascript"> var RecaptchaOptions = { ' . $options . ' }; </script>
<script type="text/javascript" src="' . $server . '/challenge?k=' . $this->public_key . $errorpart . '"></script>
<noscript>
<iframe src="' . $server . '/noscript?k=' . $this->public_key . $errorpart . '" height="300" width="500" frameborder="0"></iframe><br/>
<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
<input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>
</noscript>';
}
/**
* Calls an HTTP POST function to verify if the user's guess was correct
* #param string $remoteip
* #param string $challenge
* #param string $response
* #param array $extra_params an array of extra variables to post to the server
* #return ReCaptchaResponse
*/
function recaptcha_check_answer($remoteip = null, $challenge = null, $response = null, $extra_params = array())
{
if ($this->privkey == null || $this->privkey == '') {
die ("To use reCAPTCHA you must get an API key from <a href='https://www.google.com/recaptcha/admin/create'>https://www.google.com/recaptcha/admin/create</a>");
}
$remoteip = ($remoteip == null) ? $_SERVER['REMOTE_ADDR'] : $remoteip;
$challenge = ($challenge == null) ? $this->_ci->input->post('recaptcha_challenge_field') : $challenge;
$response = ($response == null) ? $this->_ci->input->post('recaptcha_response_field') : $response;
if ($remoteip == null || $remoteip == '') {
die ("For security reasons, you must pass the remote ip to reCAPTCHA");
}
//discard spam submissions
if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0) {
$this->is_valid = false;
$this->error = 'incorrect-captcha-sol';
}
$response = $this->recaptcha_http_post(self::RECAPTCHA_VERIFY_SERVER, "/recaptcha/api/verify",
array(
'privatekey' => $this->privkey,
'remoteip' => $remoteip,
'challenge' => $challenge,
'response' => $response
) + $extra_params
);
$answers = explode("\n", $response [1]);
if (trim($answers [0]) == 'true') {
$this->is_valid = true;
} else {
$this->is_valid = false;
$this->error = $answers [1];
}
}
/**
* gets a URL where the user can sign up for reCAPTCHA. If your application
* has a configuration page where you enter a key, you should provide a link
* using this function.
* #param string $domain The domain where the page is hosted
* #param string $appname The name of your application
*/
function recaptcha_get_signup_url($domain = null, $appname = 'Codeigniter')
{
return "https://www.google.com/recaptcha/admin/create?" . $this->recaptcha_qsencode(array('domains' => $domain, 'app' => $appname));
}
function recaptcha_aes_pad($val)
{
$block_size = 16;
$numpad = $block_size - (strlen($val) % $block_size);
return str_pad($val, strlen($val) + $numpad, chr($numpad));
}
/* Mailhide related code */
function recaptcha_aes_encrypt($val, $ky)
{
if (!function_exists("mcrypt_encrypt")) {
die ("To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed.");
}
$mode = MCRYPT_MODE_CBC;
$enc = MCRYPT_RIJNDAEL_128;
$val = $this->recaptcha_aes_pad($val);
return mcrypt_encrypt($enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
}
function recaptcha_mailhide_urlbase64($x)
{
return strtr(base64_encode($x), '+/', '-_');
}
/* gets the reCAPTCHA Mailhide url for a given email, public key and private key */
function recaptcha_mailhide_url($email)
{
if ($this->public_key == '' || $this->public_key == null || $this->privkey == "" || $this->privkey == null) {
die ("To use reCAPTCHA Mailhide, you have to sign up for a public and private key, " .
"you can do so at <a href='http://www.google.com/recaptcha/mailhide/apikey'>http://www.google.com/recaptcha/mailhide/apikey</a>");
}
$ky = pack('H*', $this->privkey);
$cryptmail = $this->recaptcha_aes_encrypt($email, $ky);
return "http://www.google.com/recaptcha/mailhide/d?k=" . $this->public_key . "&c=" . $this->recaptcha_mailhide_urlbase64($cryptmail);
}
/**
* gets the parts of the email to expose to the user.
* eg, given johndoe#example,com return ["john", "example.com"].
* the email is then displayed as john...#example.com
*/
function recaptcha_mailhide_email_parts($email)
{
$arr = preg_split("/#/", $email);
if (strlen($arr[0]) <= 4) {
$arr[0] = substr($arr[0], 0, 1);
} else if (strlen($arr[0]) <= 6) {
$arr[0] = substr($arr[0], 0, 3);
} else {
$arr[0] = substr($arr[0], 0, 4);
}
return $arr;
}
/**
* Gets html to display an email address given a public an private key.
* to get a key, go to:
*
* http://www.google.com/recaptcha/mailhide/apikey
*/
function recaptcha_mailhide_html($email)
{
$emailparts = $this->recaptcha_mailhide_email_parts($email);
$url = $this->recaptcha_mailhide_url($this->public_key, $this->privkey, $email);
return htmlentities($emailparts[0]) . "<a href='" . htmlentities($url) .
"' onclick=\"window.open('" . htmlentities($url) . "', '', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=300'); return false;\" title=\"Reveal this e-mail address\">...</a>#" . htmlentities($emailparts [1]);
}
function checkIfIsValid()
{
if ($this->getIsValid()) {
return $this->getIsValid();
} else {
return array($this->getIsValid(), $this->getError());
}
}
function getIsValid()
{
return $this->is_valid;
}
function getError()
{
return $this->error;
}
}
Use it:
$this->load->library('recaptcha');
$this->recaptcha->recaptcha_check_answer();
if (!$this->recaptcha->getIsValid()) {
$this->session->set_flashdata('error', 'Código Captcha incorrecto');
redirect(base_url() . 'add');
}
unset($post['recaptcha_challenge_field']);
unset($post['recaptcha_response_field']);
My host confirmed that Zend 2.3 is installed. I then proceeded to check the installation was working by uploading this script:
http://www.jarodmorris.com/zend_check.php
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license#zend.com so we can send you a copy immediately.
*
* #category Zend
* #package Zend_Gdata
* #subpackage Demos
* #copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* #license http://framework.zend.com/license/new-bsd New BSD License
*/
/**
* Simple class to verify that the server that this is run on has a correct
* installation of the Zend Framework Gdata component.
*/
class InstallationChecker {
const CSS_WARNING = '.warning { color: #fff; background-color: #AF0007;}';
const CSS_SUCCESS = '.success { color: #000; background-color: #69FF4F;}';
const CSS_ERROR = '.error { color: #fff; background-color: #FF9FA3;}';
const PHP_EXTENSION_ERRORS = 'PHP Extension Errors';
const PHP_MANUAL_LINK_FRAGMENT = 'http://us.php.net/manual/en/book.';
const PHP_REQUIREMENT_CHECKER_ID = 'PHP Requirement checker v0.1';
const SSL_CAPABILITIES_ERRORS = 'SSL Capabilities Errors';
const YOUTUBE_API_CONNECTIVITY_ERRORS = 'YouTube API Connectivity Errors';
const ZEND_GDATA_INSTALL_ERRORS = 'Zend Framework Installation Errors';
const ZEND_SUBVERSION_URI = 'http://framework.zend.com/download/subversion';
private static $REQUIRED_EXTENSIONS = array(
'ctype', 'dom', 'libxml', 'spl', 'standard', 'openssl');
private $_allErrors = array(
self::PHP_EXTENSION_ERRORS => array(
'tested' => false, 'errors' => null),
self::ZEND_GDATA_INSTALL_ERRORS => array(
'tested' => false, 'errors' => null),
self::SSL_CAPABILITIES_ERRORS => array(
'tested' => false, 'errors' => null),
self::YOUTUBE_API_CONNECTIVITY_ERRORS => array(
'tested' => false, 'errors' => null)
);
private $_sapiModeCLI = null;
/**
* Create a new InstallationChecker object and run verifications.
* #return void
*/
public function __construct()
{
$this->determineIfInCLIMode();
$this->runAllVerifications();
$this->outputResults();
}
/**
* Set the sapiModeCLI variable to true if we are running CLI mode.
*
* #return void
*/
private function determineIfInCLIMode()
{
if (php_sapi_name() == 'cli') {
$this->_sapiModeCLI = true;
}
}
/**
* Getter for sapiModeCLI variable.
*
* #return boolean True if we are running in CLI mode.
*/
public function runningInCLIMode()
{
if ($this->_sapiModeCLI) {
return true;
} else {
return false;
}
}
/**
* Run verifications, stopping at each step if there is a failure.
*
* #return void
*/
public function runAllVerifications()
{
if (!$this->validatePHPExtensions()) {
return;
}
if (!$this->validateZendFrameworkInstallation()) {
return;
}
if (!$this->testSSLCapabilities()) {
return;
}
if (!$this->validateYouTubeAPIConnectivity()) {
return;
}
}
/**
* Validate that the required PHP Extensions are installed and available.
*
* #return boolean False if there were errors.
*/
private function validatePHPExtensions()
{
$phpExtensionErrors = array();
foreach (self::$REQUIRED_EXTENSIONS as $requiredExtension) {
if (!extension_loaded($requiredExtension)) {
$requiredExtensionError = $requiredExtension .
' extension missing';
$documentationLink = null;
if ($requiredExtension != 'standard') {
$documentationLink = self::PHP_MANUAL_LINK_FRAGMENT .
$requiredExtension . '.php';
$documentationLink =
$this->checkAndAddHTMLLink($documentationLink);
} else {
$documentationLink = self::PHP_MANUAL_LINK_FRAGMENT .
'spl.php';
$documentationLink =
$this->checkAndAddHTMLLink($documentationLink);
}
if ($documentationLink) {
$phpExtensionErrors[] = $requiredExtensionError .
' - refer to ' . $documentationLink;
}
}
}
$this->_allErrors[self::PHP_EXTENSION_ERRORS]['tested'] = true;
if (count($phpExtensionErrors) > 0) {
$this->_allErrors[self::PHP_EXTENSION_ERRORS]['errors'] =
$phpExtensionErrors;
return false;
}
return true;
}
/**
* Validate that the Gdata component of Zend Framework is installed
* properly. Also checks that the required YouTube API helper methods are
* found.
*
* #return boolean False if there were errors.
*/
private function validateZendFrameworkInstallation()
{
$zendFrameworkInstallationErrors = array();
$zendLoaderPresent = false;
try {
$zendLoaderPresent = #fopen('Zend/Loader.php', 'r', true);
} catch (Exception $e) {
$zendFrameworkInstallationErrors[] = 'Exception thrown trying to ' .
'access Zend/Loader.php using \'use_include_path\' = true ' .
'Make sure you include the Zend Framework in your ' .
'include_path which currently contains: "' .
ini_get('include_path') . '"';
}
if ($zendLoaderPresent) {
#fclose($zendLoaderPresent);
require_once('Zend/Loader.php');
require_once('Zend/Version.php');
Zend_Loader::loadClass('Zend_Gdata_YouTube');
Zend_Loader::loadClass('Zend_Gdata_YouTube_VideoEntry');
$yt = new Zend_Gdata_YouTube();
$videoEntry = $yt->newVideoEntry();
if (!method_exists($videoEntry, 'setVideoTitle')) {
$zendFrameworkMessage = 'Your version of the ' .
'Zend Framework ' . Zend_Version::VERSION . ' is too old' .
' to run the YouTube demo application and does not' .
' contain the new helper methods. Please check out a' .
' newer version from Zend\'s repository: ' .
checkAndAddHTMLLink(self::ZEND_SUBVERSION_URI);
$zendFrameworkInstallationErrors[] = $zendFrameworkMessage;
}
} else {
if (count($zendFrameworkInstallationErrors) < 1) {
$zendFrameworkInstallationErrors[] = 'Exception thrown trying' .
' to access Zend/Loader.php using \'use_include_path\' =' .
' true. Make sure you include Zend Framework in your' .
' include_path which currently contains: ' .
ini_get('include_path');
}
}
$this->_allErrors[self::ZEND_GDATA_INSTALL_ERRORS]['tested'] = true;
if (count($zendFrameworkInstallationErrors) > 0) {
$this->_allErrors[self::ZEND_GDATA_INSTALL_ERRORS]['errors'] =
$zendFrameworkInstallationErrors;
return false;
}
return true;
}
/**
* Create HTML link from an input string if not in CLI mode.
*
* #param string The error message to be converted to a link.
* #return string Either the original error message or an HTML version.
*/
private function checkAndAddHTMLLink($inputString) {
if (!$this->runningInCLIMode()) {
return $this->makeHTMLLink($inputString);
} else {
return $inputString;
}
}
/**
* Create an HTML link from a string.
*
* #param string The string to be made into link text and anchor target.
* #return string HTML link.
*/
private function makeHTMLLink($inputString)
{
return '<a href="'. $inputString . '" target="_blank">' .
$inputString . '</a>';
}
/**
* Validate that SSL Capabilities are available.
*
* #return boolean False if there were errors.
*/
private function testSSLCapabilities()
{
$sslCapabilitiesErrors = array();
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Http_Client');
$httpClient = new Zend_Http_Client(
'https://www.google.com/accounts/AuthSubRequest');
$response = $httpClient->request();
$this->_allErrors[self::SSL_CAPABILITIES_ERRORS]['tested'] = true;
if ($response->isError()) {
$sslCapabilitiesErrors[] = 'Response from trying to access' .
' \'https://www.google.com/accounts/AuthSubRequest\' ' .
$response->getStatus() . ' - ' . $response->getMessage();
}
if (count($sslCapabilitiesErrors) > 0) {
$this->_allErrors[self::SSL_CAPABILITIES_ERRORS]['errors'] =
$sslCapabilitiesErrors;
return false;
}
return true;
}
/**
* Validate that we can connect to the YouTube API.
*
* #return boolean False if there were errors.
*/
private function validateYouTubeAPIConnectivity()
{
$connectivityErrors = array();
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata_YouTube');
$yt = new Zend_Gdata_YouTube();
$topRatedFeed = $yt->getTopRatedVideoFeed();
if ($topRatedFeed instanceof Zend_Gdata_YouTube_VideoFeed) {
if ($topRatedFeed->getTotalResults()->getText() < 1) {
$connectivityErrors[] = 'There was less than 1 video entry' .
' in the \'Top Rated Video Feed\'';
}
} else {
$connectivityErrors[] = 'The call to \'getTopRatedVideoFeed()\' ' .
'did not result in a Zend_Gdata_YouTube_VideoFeed object';
}
$this->_allErrors[self::YOUTUBE_API_CONNECTIVITY_ERRORS]['tested'] =
true;
if (count($connectivityErrors) > 0) {
$this->_allErrors[self::YOUTUBE_API_CONNECTIVITY_ERRORS]['tested'] =
$connectivityErrors;
return false;
}
return true;
}
/**
* Dispatch a call to outputResultsInHTML or outputResultsInText pending
* the current SAPI mode.
*
* #return void
*/
public function outputResults()
{
if ($this->_sapiModeCLI) {
print $this->getResultsInText();
} else {
print $this->getResultsInHTML();
}
}
/**
* Return a string representing the results of the verifications.
*
* #return string A string representing the results.
*/
private function getResultsInText()
{
$output = "== Ran PHP Installation Checker using CLI ==\n";
$error_count = 0;
foreach($this->_allErrors as $key => $value) {
$output .= $key . ' -- ';
if (($value['tested'] == true) && (count($value['errors']) == 0)) {
$output .= "No errors found\n";
} elseif ($value['tested'] == true) {
$output .= "Tested\n";
$error_count = 0;
foreach ($value['errors'] as $error) {
$output .= "Error number: " . $error_count . "\n--" .
$error . "\n";
}
} else {
$output .= "Not tested\n";
}
$error_count++;
}
return $output;
}
/**
* Return an HTML table representing the results of the verifications.
*
* #return string An HTML string representing the results.
*/
private function getResultsInHTML()
{
$html = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" " .
"\"http://www.w3.org/TR/html4/strict.dtd\">\n".
"<html><head>\n<title>PHP Installation Checker</title>\n" .
"<style type=\"text/css\">\n" .
self::CSS_WARNING . "\n" .
self::CSS_SUCCESS . "\n" .
self::CSS_ERROR . "\n" .
"</style></head>\n" .
"<body>\n<table class=\"verification_table\">" .
"<caption>Ran PHP Installation Checker on " .
gmdate('c') . "</caption>\n";
$error_count = 0;
foreach($this->_allErrors as $key => $value) {
$html .= "<tr><td class=\"verification_type\">" . $key . "</td>";
if (($value['tested'] == true) && (count($value['errors']) == 0)) {
$html .= "<td class=\"success\">Tested</td></tr>\n" .
"<tr><td colspan=\"2\">No errors found</td></tr>\n";
} elseif ($value['tested'] == true) {
$html .= "<td class=\"warning\">Tested</td></tr>\n";
$error_count = 0;
foreach ($value['errors'] as $error) {
$html .= "<tr><td class=\"error\">" . $error_count . "</td>" .
"<td class=\"error\">" . $error . "</td></tr>\n";
}
} else {
$html .= "<td class=\"warning\">Not tested</td></tr>\n";
}
$error_count++;
}
$html .= "</body></html>";
return $html;
}
}
$installationChecker = new InstallationChecker();
Go to the above link to see the results. Specifically, I'm interested in this error message:
Exception thrown trying to access Zend/Loader.php using 'use_include_path' = true.
Make sure you include Zend Framework in your include_path which currently contains:
.:/usr/lib/php:/usr/local/lib/php
Here is the link to my php info printout: http://www.jarodmorris.com/cms/phpinfo.php
I've obtained the Zend Framework from the zend website and uploaded it to a /zend folder on my website. For whatever reason, my host won't give me access to the php.ini file. I have purchased a reseller account with my host.
I'm doing all of this because I want to integrate Google Calendar API into an application I'm building on one of my websites. Maybe there is a simpler solution to my ultimate goal, but I don't see it.
Thanks for pointing me in the right direction.
EDITED TO SHOW CURRENT PHP CODE WHERE INCLUDE IS CONCERNED:
set_include_path(get_include_path() . PATH_SEPARATOR . "/home/jarodmo/public_html/zend/library");
echo get_include_path();
echo "<br>";
///home/jarodmo/public_html/zend/library/Zend
Add the dir to your include path:
set_include_path(
get_include_path()
. PATH_SEPARATOR
. '/whatever/your/zend/dir/is');
A default error logging using vqmod is as follows:
---------- Date: 2012-10-09 19:46:06 ~ IP : 127.0.0.1 ----------
REQUEST URI : /oc/
MOD DETAILS:
modFile : C:\wamp\www\oc\vqmod\xml\templace.xml
id : Template
version : 1.5.2 - 1.5.2.1
vqmver : 1.0.8
author : templace.com
SEARCH NOT FOUND (ABORTING MOD): require_once(foo . 'library/template.php');
----------------------------------------------------------------------
Example vqmod causing the error
<modification>
<id>Templace</id>
<version>1.5.2 - 1.5.2.1</version>
<author>templace.com</author>
<vqmver>1.0.8</vqmver>
<file name="system/startup.php">
<operation>
<search position="before"><![CDATA[
require_once(foo . 'library/template.php');
]]></search>
<add><![CDATA[
require_once(DIR_SYSTEM . 'library/templace.php');
]]></add>
</operation>
</file>
</modification>
To resole this issue I would have to open the vqmod file templace.xml and search for the file[name] this error is referring too.
QUESTION: How could I add the parent file[name] the actual error is referring too?
E.g adding: "system/startup.php" to the error message to make it easier to debug.
vqmod.php
/**
* VQMod
* #description Main Object used
*/
final class VQMod {
private $_vqversion = '2.1.7';
private $_modFileList = array();
private $_mods = array();
private $_filesModded = array();
private $_cwd = '';
private $_doNotMod = array();
private $_virtualMode = true;
public $useCache = false;
public $logFilePath = 'vqmod/vqmod.log';
public $vqCachePath = 'vqmod/vqcache/';
public $protectedFilelist = 'vqmod/vqprotect.txt';
public $logging = true;
public $cacheTime = 5; // local=5secs live=60secs
public $log;
/**
* VQMod::__construct()
*
* #param bool $path File path to use
* #param bool $logging Enable/disabled logging
* #return null
* #description Startup of VQMod
*/
public function __construct($path = false, $logging = true) {
if(!class_exists('DOMDocument')) {
die('ERROR - YOU NEED DOMDocument INSTALLED TO USE VQMod');
}
if(!$path){
$path = dirname(dirname(__FILE__));
}
$this->_setCwd($path);
$this->logging = (bool) $logging;
$this->log = new VQModLog($this);
$this->_getMods();
$this->_loadProtected();
}
/**
* VQMod::modCheck()
*
* #param string $sourceFile path for file
* #return string
* #description Checks if a file has modifications and applies them, returning cache files or the file name
*/
public function modCheck($sourceFile) {
if(!preg_match('%^([a-z]:)?[\\\\/]%i', $sourceFile)) {
$sourcePath = $this->path($sourceFile);
} else {
$sourcePath = realpath($sourceFile);
}
if(!$sourcePath || is_dir($sourcePath) || in_array($sourcePath, $this->_doNotMod)) {
return $sourceFile;
}
$stripped_filename = preg_replace('~^' . preg_quote($this->getCwd(), '~') . '~', '', $sourcePath);
$cacheFile = $this->_cacheName($stripped_filename);
if($this->useCache && file_exists($cacheFile)) {
//return $cacheFile; // useCache being Deprecated in favor of cacheTime
}
if(isset($this->_filesModded[$sourcePath])) {
return $this->_filesModded[$sourcePath]['cached'] ? $cacheFile : $sourceFile;
}
$changed = false;
$fileHash = sha1_file($sourcePath);
$fileData = file_get_contents($sourcePath);
foreach($this->_mods as $modObject) {
foreach($modObject->mods as $path => $mods) {
if($this->_checkMatch($path, $sourcePath)) {
$modObject->applyMod($mods, $fileData);
}
}
}
// START QPHORIA CACHELOCK CODE
//
if (sha1($fileData) != $fileHash) {
$writePath = $cacheFile;
$cacheLock = false;
if(file_exists($writePath) && ((filemtime($writePath) + (float)$this->cacheTime) >= time())) {
$cacheLock = true;
$changed = true;
}
if(!$cacheLock && (!file_exists($writePath) || is_writable($writePath))) {
file_put_contents($writePath, $fileData);
$changed = true;
} else {
//file_put_contents('./cachelock.txt', "$writePath \r\n", FILE_APPEND); // debugging only.
}
//file_put_contents('./cachetotal.txt', "$writePath \r\n", FILE_APPEND);
} // END QPHORIA CACHELOCK CODE
/* Original Code
if(sha1($fileData) != $fileHash) {
$writePath = $this->_virtualMode ? $cacheFile : $sourcePath;
if(!file_exists($writePath) || is_writable($writePath)) {
file_put_contents($writePath, $fileData);
$changed = true;
}
}*/
$this->_filesModded[$sourcePath] = array('cached' => $changed);
return $changed ? $writePath : $sourcePath;
}
/**
* VQMod::path()
*
* #param string $path File path
* #param bool $skip_real If true path is full not relative
* #return bool, string
* #description Returns the full true path of a file if it exists, otherwise false
*/
public function path($path, $skip_real = false) {
$tmp = $this->_cwd . $path;
$realpath = $skip_real ? $tmp : realpath($tmp);
if(!$realpath) {
return false;
}
if(is_dir($realpath)) {
$realpath = rtrim($realpath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
}
return $realpath;
}
/**
* VQMod::getCwd()
*
* #return string
* #description Returns current working directory
*/
public function getCwd() {
return $this->_cwd;
}
/**
* VQMod::_getMods()
*
* #return null
* #description Gets list of XML files in vqmod xml folder for processing
*/
private function _getMods() {
$this->_modFileList = glob($this->path('vqmod/xml/') . '*.xml');
if($this->_modFileList) {
$this->_parseMods();
} else {
$this->log->write('NO MODS IN USE');
}
}
/**
* VQMod::_parseMods()
*
* #return null
* #description Loops through xml files and attempts to load them as VQModObject's
*/
private function _parseMods() {
$dom = new DOMDocument('1.0', 'UTF-8');
foreach($this->_modFileList as $modFileKey => $modFile) {
if(file_exists($modFile)) {
if(#$dom->load($modFile)) {
$mod = $dom->getElementsByTagName('modification')->item(0);
$this->_mods[] = new VQModObject($mod, $modFile, $this);
} else {
$this->log->write('DOM UNABLE TO LOAD: ' . $modFile);
}
} else {
$this->log->write('FILE NOT FOUND: ' . $modFile);
}
}
}
/**
* VQMod::_loadProtected()
*
* #return null
* #description Loads protected list and adds them to _doNotMod array
*/
private function _loadProtected() {
$file = $this->path($this->protectedFilelist);
if($file && is_file($file)) {
$protected = file_get_contents($file);
if(!empty($protected)) {
$protected = preg_replace('~\r?\n~', "\n", $protected);
$paths = explode("\n", $protected);
foreach($paths as $path) {
$fullPath = $this->path($path);
if($fullPath && !in_array($fullPath, $this->_doNotMod)) {
$this->_doNotMod[] = $fullPath;
}
}
}
}
}
/**
* VQMod::_cacheName()
*
* #param string $file Filename to be converted to cache filename
* #return string
* #description Returns cache file name for a path
*/
private function _cacheName($file) {
return $this->path($this->vqCachePath) . 'vq2-' . preg_replace('~[/\\\\]+~', '_', $file);
}
/**
* VQMod::_setCwd()
*
* #param string $path Path to be used as current working directory
* #return null
* #description Sets the current working directory variable
*/
private function _setCwd($path) {
$realpath = realpath($path);
if(!$realpath) {
die('COULDNT RESOLVE CWD REALPATH');
}
$this->_cwd = rtrim($realpath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
}
/**
* VQMod::_checkMatch()
*
* #param string $modFilePath Modification path from a <file> node
* #param string $checkFilePath File path
* #return bool
* #description Checks a modification path against a file path
*/
private function _checkMatch($modFilePath, $checkFilePath) {
$modFilePath = str_replace('\\', '/', $modFilePath);
$checkFilePath = str_replace('\\', '/', $checkFilePath);
$modFilePath = preg_replace('/([^*]+)/e', 'preg_quote("$1", "~")', $modFilePath);
$modFilePath = str_replace('*', '[^/]*', $modFilePath);
$return = (bool) preg_match('~^' . $modFilePath . '$~', $checkFilePath);
return $return;
}
}
/**
* VQModLog
* #description Object to log information to a file
*/
class VQModLog {
private $_sep;
private $_vqmod;
private $_defhash = 'da39a3ee5e6b4b0d3255bfef95601890afd80709';
private $_logs = array();
/**
* VQModLog::__construct()
*
* #param VQMod $vqmod VQMod main class as reference
* #return null
* #description Object instantiation method
*/
public function __construct(VQMod $vqmod) {
$this->_vqmod = $vqmod;
$this->_sep = str_repeat('-', 70);
}
/**
* VQModLog::__destruct()
*
* #return null
* #description Logs any messages to the log file just before object is destroyed
*/
public function __destruct() {
if(empty($this->_logs) || $this->_vqmod->logging == false) {
return;
}
$txt = array();
$txt[] = str_repeat('-', 10) . ' Date: ' . date('Y-m-d H:i:s') . ' ~ IP : ' . (isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : 'N/A') . ' ' . str_repeat('-', 10);
$txt[] = 'REQUEST URI : ' . $_SERVER['REQUEST_URI'];
foreach($this->_logs as $count => $log) {
if($log['obj']) {
$vars = get_object_vars($log['obj']);
$txt[] = 'MOD DETAILS:';
foreach($vars as $k => $v) {
if(is_string($v)) {
$txt[] = ' ' . str_pad($k, 10, ' ', STR_PAD_RIGHT) . ': ' . $v;
}
}
}
foreach($log['log'] as $msg) {
$txt[] = $msg;
}
if ($count > count($this->_logs)-1) {
$txt[] = '';
}
}
$txt[] = $this->_sep;
$txt[] = str_repeat(PHP_EOL, 2);
$logPath = $this->_vqmod->path($this->_vqmod->logFilePath, true);
if(!file_exists($logPath)) {
$res = file_put_contents($logPath, '');
if($res === false) {
die('COULD NOT WRITE TO LOG FILE');
}
}
file_put_contents($logPath, implode(PHP_EOL, $txt), FILE_APPEND);
}
/**
* VQModLog::write()
*
* #param string $data Text to be added to log file
* #param VQModObject $obj Modification the error belongs to
* #return null
* #description Adds error to log object ready to be output
*/
public function write($data, VQModObject $obj = NULL) {
if($obj) {
$hash = sha1($obj->id);
} else {
$hash = $this->_defhash;
}
if(empty($this->_logs[$hash])) {
$this->_logs[$hash] = array(
'obj' => $obj,
'log' => array()
);
}
$this->_logs[$hash]['log'][] = $data;
}
}
/**
* VQModObject
* #description Object for the <modification> that orchestrates each applied modification
*/
class VQModObject {
public $modFile = '';
public $id = '';
public $version = '';
public $vqmver = '';
public $author = '';
public $mods = array();
private $_vqmod;
private $_skip = false;
/**
* VQModObject::__construct()
*
* #param DOMNode $node <modification> node
* #param string $modFile File modification is from
* #param VQMod $vqmod VQMod object as reference
* #return null
* #description Loads modification meta information
*/
public function __construct(DOMNode $node, $modFile, VQmod $vqmod) {
if($node->hasChildNodes()) {
foreach($node->childNodes as $child) {
$name = (string) $child->nodeName;
if(isset($this->$name)) {
$this->$name = (string) $child->nodeValue;
}
}
}
$this->modFile = $modFile;
$this->_vqmod = $vqmod;
$this->_parseMods($node);
}
/**
* VQModObject::skip()
*
* #return bool
* #description Returns the skip status of a modification
*/
public function skip() {
return $this->_skip;
}
/**
* VQModObject::applyMod()
*
* #param array $mods Array of search add nodes
* #param string $data File contents to be altered
* #return null
* #description Applies all modifications to the text data
*/
public function applyMod($mods, &$data) {
if($this->_skip) return;
$tmp = $data;
foreach($mods as $mod) {
$indexCount = 0;
$tmp = $this->_explodeData($tmp);
$lineMax = count($tmp) - 1;
switch($mod['search']->position) {
case 'top':
$tmp[$mod['search']->offset] = $mod['add']->getContent() . $tmp[$mod['search']->offset];
break;
case 'bottom':
$offset = $lineMax - $mod['search']->offset;
if($offset < 0){
$tmp[-1] = $mod['add']->getContent();
} else {
$tmp[$offset] .= $mod['add']->getContent();
}
break;
case 'all':
$tmp = array($mod['add']->getContent());
break;
default:
$changed = false;
foreach($tmp as $lineNum => $line) {
if($mod['search']->regex == 'true') {
$pos = #preg_match($mod['search']->getContent(), $line);
if($pos === false) {
if($mod['error'] == 'log' || $mod['error'] == 'abort' ) {
$this->_vqmod->log->write('INVALID REGEX ERROR - ' . $mod['search']->getContent(), $this);
}
continue 2;
} elseif($pos == 0) {
$pos = false;
}
} else {
$pos = strpos($line, $mod['search']->getContent());
}
if($pos !== false) {
$indexCount++;
$changed = true;
if(!$mod['search']->indexes() || ($mod['search']->indexes() && in_array($indexCount, $mod['search']->indexes()))) {
switch($mod['search']->position) {
case 'before':
$offset = ($lineNum - $mod['search']->offset < 0) ? -1 : $lineNum - $mod['search']->offset;
$tmp[$offset] = empty($tmp[$offset]) ? $mod['add']->getContent() : $mod['add']->getContent() . "\n" . $tmp[$offset];
break;
case 'after':
$offset = ($lineNum + $mod['search']->offset > $lineMax) ? $lineMax : $lineNum + $mod['search']->offset;
$tmp[$offset] = $tmp[$offset] . "\n" . $mod['add']->getContent();
break;
default:
if(!empty($mod['search']->offset)) {
for($i = 1; $i <= $mod['search']->offset; $i++) {
if(isset($tmp[$lineNum + $i])) {
$tmp[$lineNum + $i] = '';
}
}
}
if($mod['search']->regex == 'true') {
$tmp[$lineNum] = preg_replace($mod['search']->getContent(), $mod['add']->getContent(), $line);
} else {
$tmp[$lineNum] = str_replace($mod['search']->getContent(), $mod['add']->getContent(), $line);
}
break;
}
}
}
}
if(!$changed) {
$skip = ($mod['error'] == 'skip' || $mod['error'] == 'log') ? ' (SKIPPED)' : ' (ABORTING MOD)';
if($mod['error'] == 'log' || $mod['error'] == 'abort') {
$this->_vqmod->log->write('SEARCH NOT FOUND' . $skip . ': ' . $mod['search']->getContent(), $this);
}
if($mod['error'] == 'abort') {
$this->_skip = true;
return;
}
}
break;
}
ksort($tmp);
$tmp = $this->_implodeData($tmp);
}
$data = $tmp;
}
/**
* VQModObject::_parseMods()
*
* #param DOMNode $node <modification> node to be parsed
* #return null
* #description Parses modifications in preparation for the applyMod method to work
*/
private function _parseMods(DOMNode $node){
$files = $node->getElementsByTagName('file');
foreach($files as $file) {
$fileToMod = $file->getAttribute('name');
$error = ($file->hasAttribute('error')) ? $file->getAttribute('error') : 'log';
$fullPath = $this->_vqmod->path($fileToMod);
if(!$fullPath){
if(strpos($fileToMod, '*') !== false) {
$fullPath = $this->_vqmod->getCwd() . $fileToMod;
} else {
if ($error == 'log' || $error == 'abort') {
$skip = ($error == 'log') ? ' (SKIPPED)' : ' (ABORTING MOD)';
$this->_vqmod->log->write('Could not resolve path for [' . $fileToMod . ']' . $skip, $this);
}
if ($error == 'log' || $error == 'skip') {
continue;
} elseif ($error == 'abort') {
return false;
}
}
}
$operations = $file->getElementsByTagName('operation');
foreach($operations as $operation) {
$error = ($operation->hasAttribute('error')) ? $operation->getAttribute('error') : 'abort';
$this->mods[$fullPath][] = array(
'search' => new VQSearchNode($operation->getElementsByTagName('search')->item(0)),
'add' => new VQAddNode($operation->getElementsByTagName('add')->item(0)),
'error' => $error
);
}
}
}
/**
* VQModObject::_explodeData()
*
* #param string $data File contents
* #return string
* #description Splits a file into an array of individual lines
*/
private function _explodeData($data) {
return explode("\n", $data);
}
/**
* VQModObject::_implodeData()
*
* #param array $data Array of lines
* #return string
* #description Joins an array of lines back into a text file
*/
private function _implodeData($data) {
return implode("\n", $data);
}
}
/**
* VQNode
* #description Basic node object blueprint
*/
class VQNode {
public $trim = 'false';
private $_content = '';
/**
* VQNode::__construct()
*
* #param DOMNode $node Search/add node
* #return null
* #description Parses the node attributes and sets the node property
*/
public function __construct(DOMNode $node) {
$this->_content = $node->nodeValue;
if($node->hasAttributes()) {
foreach($node->attributes as $attr) {
$name = $attr->nodeName;
if(isset($this->$name)) {
$this->$name = $attr->nodeValue;
}
}
}
}
/**
* VQNode::getContent()
*
* #return string
* #description Returns the content, trimmed if applicable
*/
public function getContent() {
$content = ($this->trim == 'true') ? trim($this->_content) : $this->_content;
return $content;
}
}
/**
* VQSearchNode
* #description Object for the <search> xml tags
*/
class VQSearchNode extends VQNode {
public $position = 'replace';
public $offset = 0;
public $index = 'false';
public $regex = 'false';
public $trim = 'true';
/**
* VQSearchNode::indexes()
*
* #return bool, array
* #description Returns the index values to use the search on, or false if none
*/
public function indexes() {
if($this->index == 'false') {
return false;
}
$tmp = explode(',', $this->index);
foreach($tmp as $k => $v) {
if(!is_int($v)) {
unset($k);
}
}
$tmp = array_unique($tmp);
return empty($tmp) ? false : $tmp;
}
}
/**
* VQAddNode
* #description Object for the <add> xml tags
*/
class VQAddNode extends VQNode {
}
Also couple of other ideas to make debugging even easier:
List any other vqmod files which have previously edited this same file.
This is another common issue where I find when two extensions are editing the same file and the latter is causing the error but it would be useful to know about any other vqmods editing the same file. Yes I suppose I could add error="skip" to everything but dont think this is the best approach to just hide all of the errors, the user should be made aware there is an error...
"Suggested Fix", maybe some smart way you can test what type of error it is.
Contradict what I said above but even at its most basic form you could suggest hiding the error if its not essential. So that anybody can read it and understand how it fix it.
E.g
OPEN: vqmod/xml/templace.xml (line:23)
FIND: <operation>
REPLACE <operation error="skip">
Adding the line number in the XML file the error is coming from. It would be lovely not having to search all of the time and could quickly go to the line number in the vqmod
The issue for the file being edited is certainly one that is way overdue and one I plan on adding in the next release of vQmod. As for the other suggestions
Interesting idea, and one that could certainly be considered. The only problem I see with this is that it would possibly make some log files enormous
This is going to be next to impossible to incorporate
This is impossible without some pretty expensive runtime. The error doesn't lie in the XML as such, so would require re-opening the xml that's been parsed, searching for the line in question line by line and then reporting that. it sounds simple, but you have to remember that xml's can have the same search parameter for multiple operations - so in that situation you'd be no better off than searching the file yourself
Is there any way in PHP to do static code analysis and detect reliance on the register_globals initiative? It's relatively straightforward to manually examine a file and look for variables which have not been initialized and infer from that that these may be relying on it, but I need to do this for many hundreds of scripts, so I'm looking for an automated solution.
My last resort is setting up a dev environment with the directive turned off and strict error reporting and letting QA play around for a long while, then fix the instances that the error log catches, but this is not guaranteed to find 100% of the cases, and certainly not a good use of resources if an automated solution exists.
A small script I just hacked together to detect simple undefined variables. You'll need PHP-Parser for this:
<?php
error_reporting(E_ALL);
$dir = './foo';
require_once './lib/bootstrap.php';
class Scope {
protected $stack;
protected $pos;
public function __construct() {
$this->stack = array();
$this->pos = -1;
}
public function addVar($name) {
$this->stack[$this->pos][$name] = true;
}
public function hasVar($name) {
return isset($this->stack[$this->pos][$name]);
}
public function pushScope() {
$this->stack[++$this->pos] = array();
}
public function popScope() {
--$this->pos;
}
}
class UndefinedVariableVisitor extends PHPParser_NodeVisitorAbstract {
protected $scope;
protected $parser;
protected $traverser;
public function __construct(Scope $scope, PHPParser_Parser $parser, PHPParser_NodeTraverser $traverser) {
$this->scope = $scope;
$this->parser = $parser;
$this->traverser = $traverser;
}
public function enterNode(PHPParser_Node $node) {
if (($node instanceof PHPParser_Node_Expr_Assign || $node instanceof PHPParser_Node_Expr_AssignRef)
&& $node->var instanceof PHPParser_Node_Expr_Variable
&& is_string($node->var->name)
) {
$this->scope->addVar($node->var->name);
} elseif ($node instanceof PHPParser_Node_Stmt_Global || $node instanceof PHPParser_Node_Stmt_Static) {
foreach ($node->vars as $var) {
if (is_string($var->name)) {
$this->scope->addVar($var->name);
}
}
} elseif ($node instanceof PHPParser_Node_Expr_Variable && is_string($node->name)) {
if (!$this->scope->hasVar($node->name)) {
echo 'Undefined variable $' . $node->name . ' on line ' . $node->getLine() . "\n";
}
} elseif ($node instanceof PHPParser_Node_Stmt_Function || $node instanceof PHPParser_Node_Stmt_ClassMethod) {
$this->scope->pushScope();
// params are always available
foreach ($node->params as $param) {
$this->scope->addVar($param->name);
}
// methods always have $this
if ($node instanceof PHPParser_Node_Stmt_ClassMethod) {
$this->scope->addVar('this');
}
} elseif ($node instanceof PHPParser_Node_Expr_Include && $node->expr instanceof PHPParser_Node_Scalar_String) {
$file = $node->expr->value;
$code = file_get_contents($file);
$stmts = $this->parser->parse($code);
// for includes within the file
$cwd = getcwd();
chdir(dirname($file));
$this->traverser->traverse($stmts);
chdir($cwd);
}
}
public function leaveNode(PHPParser_Node $node) {
if ($node instanceof PHPParser_Node_Stmt_Function || $node instanceof PHPParser_Node_Stmt_ClassMethod) {
$this->scope->popScope();
}
}
}
$parser = new PHPParser_Parser(new PHPParser_Lexer());
$scope = new Scope;
$traverser = new PHPParser_NodeTraverser;
$traverser->addVisitor(new UndefinedVariableVisitor($scope, $parser, $traverser));
foreach (new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir),
RecursiveIteratorIterator::LEAVES_ONLY)
as $file
) {
if (!preg_match('/\.php$/', $file)) continue;
echo 'Checking ' . $file . ':', "\n";
$code = file_get_contents($file);
$stmts = $parser->parse($code);
// for includes within the file
$cwd = getcwd();
chdir(dirname($file));
$scope->pushScope();
$traverser->traverse($stmts);
$scope->popScope();
chdir($cwd);
echo "\n";
}
It's just a very basic implementation and I did not test it extensively, but it should work for scripts that don't go wild with $GLOBALS and $$varVars. It does basic include resolution.
This should work (from one of the php manual comments):
if (ini_get('register_globals')) {
foreach ($GLOBALS as $int_temp_name => $int_temp_value) {
if (!in_array($int_temp_name, array (
'GLOBALS',
'_FILES',
'_REQUEST',
'_COOKIE',
'_SERVER',
'_ENV',
'_SESSION',
ini_get('session.name'),
'int_temp_name',
'int_temp_value'
))) {
unset ($GLOBALS[$int_temp_name]);
}
}
}
Tweaked the code above with the latest parser: used it to make 5.4 register_globals to 7.2
<?php
/*
* pgParser.php is a "Abstract syntax tree" progam based on the Nikic PHP-Parser https://github.com/nikic/PHP-Parser
* Tweaked for use to lose register global variables.
*/
use PhpParser\Node;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitorAbstract;
use PhpParser\Parser;
error_reporting(E_ALL);
/*
* $dir contains a base dir to use when no PARAM directory eq "php ./pgParser.php /home/hrobben/php/ > results.txt"
*/
$dir = '/home/hrobben/php/';
/*
* $nonecheck : variables not to check....
* e.g ['GLOBALS','_COOKIE', 'properties'] -> $GLOBALS, $_COOKIE, $properties >>>>> will not been checked.
*/
$nonecheck = ['_COOKIE', '_SERVER', '_SESSION'];
/*
* if those names part or directory not include...
* this can be usefull when certain users (developers) have own directories
* empty = [] no directories will be excluded
* e.g. ['george', 'henry'] all directories /tree/git/base/src/henry/ and /template/george/blog/ will be excluded.
*/
$nonesubdir = ['henry', 'ckeditor'];
/*
* $excludeMatch can be filled with text in directory plus file to exclude.
* e.q. _MA. will exclude the file index_MA.php3 to scan.
* e.g. _MA will exclude the file /git/src/test_MAIN/index.php3
* be carefull.
* Not for include files, only base files.
*/
$excludeMatch = ['_HR.', '_ed.'];
/*
* you can give a base directory to begin scanning.
*/
if (count($argv) > 0) {
$dir = $argv[1];
}
require_once './vendor/autoload.php';
class Scope
{
protected $stack;
protected $pos;
public function __construct()
{
$this->stack = array();
$this->pos = -1;
}
public function addVar($name)
{
$this->stack[$this->pos][$name] = true;
}
public function hasVar($name): bool
{
return isset($this->stack[$this->pos][$name]);
}
public function pushScope()
{
$this->stack[++$this->pos] = array();
}
public function popScope()
{
--$this->pos;
}
public function getPos()
{
return $this->pos;
}
}
class UndefinedVariableVisitor extends NodeVisitorAbstract
{
protected $scope;
protected $parser;
protected $traverser;
protected $nonecheck;
protected $isInclude = false;
public function __construct(Scope $scope, Parser $parser, NodeTraverser $traverser, array $nonecheck)
{
$this->scope = $scope;
$this->parser = $parser;
$this->traverser = $traverser;
$this->nonecheck = $nonecheck;
}
public function enterNode(Node $node)
{
$includePath = ['/home/hrobben/php/include/class/'];
$nonesubdir = ['jp', 'jp117']; // for the include exclusion directories.
if (($node instanceof PhpParser\Node\Expr\Assign || $node instanceof PhpParser\Node\Expr\AssignRef)
&& $node->var instanceof PhpParser\Node\Expr\Variable
&& is_string($node->var->name)
) {
// if preg_replace uses the same var name as second argument, its not setting a var, it must also be on the first level.
if ($node->expr->name->parts[0] == 'preg_replace' && $node->expr->args[2]->value->name == $node->var->name && $this->scope->getPos() == 0) {
//echo 'found $'.$node->expr->args[2]->value->name.' level '.$this->scope->getPos()."\n";
} else {
//echo 'add var $' . $node->var->name . "\n";
$this->scope->addVar($node->var->name);
}
} elseif ($node instanceof PhpParser\Node\Stmt\Global_ || $node instanceof PhpParser\Node\Stmt\Static_) {
foreach ($node->vars as $var) {
if (is_string($var->name)) {
$this->scope->addVar($var->name);
//echo 'add global or static var $' . $var->name . "\n";
}
}
} elseif ($node instanceof PhpParser\Node\Stmt\Foreach_) {
$this->scope->addVar($node->valueVar->name);
if ($node->keyVar) {
$this->scope->addVar($node->keyVar->name);
}
} elseif ($node instanceof PhpParser\Node\Stmt\StaticVar) {
$this->scope->addVar($node->var->name);
} elseif ($node instanceof PhpParser\Node\Expr\FuncCall && ($node->name->parts[0] == 'preg_match')) {
foreach ($node->args as $args) {
if ($node->args[2]) {
$this->scope->addVar($node->args[2]->value->name);
}
}
} elseif ($node instanceof PhpParser\Node\Expr\List_) {
foreach ($node->items as $item) {
$this->scope->addVar($item->value->name);
}
} elseif ($node instanceof PhpParser\Node\Expr\Closure) {
foreach ($node->params as $param) {
$this->scope->addVar($param->var->name);
}
} elseif ($node instanceof PhpParser\Node\Expr\Variable && is_string($node->name) && !$node instanceof PhpParser\Node\Const_) {
if (!$this->scope->hasVar($node->name) && !in_array($node->name, $this->nonecheck)) {
echo 'Undefined variable $' . $node->name . ' on line ' . $node->getLine() . "\n";
}
} elseif ($node instanceof PhpParser\Node\Stmt\Function_ || $node instanceof PhpParser\Node\Stmt\ClassMethod) {
$this->scope->pushScope();
// params are always available
foreach ($node->params as $param) {
//echo 'param name : '. $param->var->name. "\n";
$this->scope->addVar($param->var->name);
}
// methods always have $this
if ($node instanceof PhpParser\Node\Stmt\ClassMethod) {
$this->scope->addVar('this');
}
} elseif ($node instanceof PhpParser\Node\Expr\Include_ && $node->expr instanceof PhpParser\Node\Scalar\String_) {
$file = $node->expr->value;
$code = file_get_contents($file);
if (strlen($code) < 5) {
foreach ($includePath as $path) {
if (strlen($code) < 5) {
$code = file_get_contents($path . $file);
}
}
}
$match_string = implode("\/|", $nonesubdir);
if (preg_match("/$match_string\//", $file)) {
$code = '';
echo 'file skipped: ' . $file . "\n";
}
$stmts = $this->parser->parse($code);
// for includes within the file
$cwd = getcwd();
chdir(dirname($file));
$this->isInclude = true;
$this->traverser->traverse($stmts);
$this->isInclude = false;
chdir($cwd);
if (strlen($code) < 5) {
echo 'Include <- ' . $file . ' not found or empty.' . "\n";
} else {
echo 'Include <- ' . $file . "\n";
}
}
}
public function leaveNode(Node $node)
{
if ($node instanceof PhpParser\Node\Stmt\Function_ || $node instanceof PhpParser\Node\Stmt\ClassMethod) {
$this->scope->popScope();
}
}
}
$lexer = new PhpParser\Lexer();
$parser = (new PhpParser\ParserFactory)->create(
PhpParser\ParserFactory::PREFER_PHP7,
$lexer
);
$scope = new Scope;
$traverser = new NodeTraverser();
$traverser->addVisitor(new UndefinedVariableVisitor($scope, $parser, $traverser, $nonecheck));
foreach (new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir),
RecursiveIteratorIterator::LEAVES_ONLY)
as $file
) {
if (!preg_match('/\.php$|\.html$|\.php3$/', $file)) continue;
$match_string = implode("\/|\/", $nonesubdir);
if (preg_match("/\/$match_string\//", $file)) continue;
$match_string = implode("|", $excludeMatch);
if (preg_match("/$match_string/", $file)) continue;
echo 'Checking ' . $file . ':', "\n";
$code = file_get_contents($file);
$stmts = $parser->parse($code);
// print_r($stmts);
// for includes within the file
$cwd = getcwd();
chdir(dirname($file));
$scope->pushScope();
$traverser->traverse($stmts);
//print_r($stmts);
$scope->popScope();
chdir($cwd);
echo "\n";
}
Used this to make a big many script files holding code to go without global registered variables. We gone use it with PHP7.2