I'm working on a PHP project that has a lot of hard coded paths in it. I'm not the main developer, just working on a small part of the project.
I'd like to be able to test my changes locally before committing them, but my directory structure is completely different. For example, there's a lot of this in the code:
require_once("/home/clientx/htdocs/include.php")
Which doesn't work on my local WAMP server because the path is different. Is there a way to tell either WAMP or XP that "/home/clientx/htdocs/" really means "c:/shared/clients/clientx"?
If its a local copy, do a search and replace on the whole directory , Please don't forget trailing slash. And when you commit the code, do reverse.
This is the solution, if you don't want to add extra variables and stuff (because that would change other developers' code/work/dependencies (if any)
search "/home/clientx/htdocs/" and replace to this: "c:/shared/clients/clientx/"
Always use $_SERVER['DOCUMENT_ROOT'] instead of hardcoded path.
require_once($_SERVER['DOCUMENT_ROOT']."/include.php")
as for your wamb environment, you will need a dedicated drive to simulate file structure. You can use NTFS tools or simple subst command to map some directory to a drive.
Create /home/clientx/htdocs/ folder on this drive and change your httpd.conf to reflect it.
But again, you will do yourself a huge favor by convincing your coworkers to stop using hardcoded paths
WARNING: ONLY USE THIS SOLUTION FOR EMERGENCY REPAIRS, NEVER FOR LONGER PRODUCTION CODE
Define a class with rewriting methods, see http://php.net/manual/en/class.streamwrapper.php
<?php
class YourEmergencyWrapper {
static $from = '/home/clientx/htdocs/';
static $to = 'c:/shared/clients/client';
private $resource = null;
//...some example stream_* functions, be sure to implement them all
function stream_open($path,$mode,$options=null,&$opened_path){
$path = self::rewrite($path);
self::restore();
$this->resource = fopen($path,$mode,$options);
self::reenable();
$opened_path = $path;
return is_resource($this->resource);
}
function stream_read($count){
self::restore();
$ret = fread($this->resource,$count);
self::reenable();
return $ret;
}
function stream_eof(){
self::restore();
$ret = feof($this->resource);
self::reenable();
return $ret;
}
function stream_stat(){
self::restore();
$ret = fstat($this->resource);
self::reenable();
return $ret;
}
static function rewrite($path){
if(strpos($path,self::$from)===0) $path = self::$to.substr($path,strlen(self::$from));
return $path;
}
//... other functions
private static function restore(){
stream_wrapper_restore('file');
}
private static function reenable(){
stream_wrapper_unregister('file');
stream_wrapper_register('file',__CLASS__);
}
}
stream_wrapper_unregister('file');
stream_wrapper_register('file','YourEmergencyWrapper');
Seriously, only some local debugging on your own dev-server. You can force it as an auto_prepend on almost any code. Left some function yet be implemented ;P
Related
I've understood there are several ways to determine the user's home, depending on the platform (mainly Unix/Linux vs Windows).
Composer uses an environment variable, in composer/Platform package:
public static function getUserDirectory()
{
if (false !== ($home = getenv('HOME'))) {
return $home;
}
if (self::isWindows() && false !== ($home = getenv('USERPROFILE'))) {
return $home;
}
if (function_exists('posix_getuid') && function_exists('posix_getpwuid')) {
$info = posix_getpwuid(posix_getuid());
return $info['dir'];
}
throw new \RuntimeException('Could not determine user directory');
}
public static function isWindows()
{
return defined('PHP_WINDOWS_VERSION_BUILD');
}
Webmozart's path-util package uses other environment variables:
public static function getHomeDirectory()
{
// For UNIX support
if (getenv('HOME')) {
return static::canonicalize(getenv('HOME'));
}
// For >= Windows8 support
if (getenv('HOMEDRIVE') && getenv('HOMEPATH')) {
return static::canonicalize(getenv('HOMEDRIVE').getenv('HOMEPATH'));
}
throw new RuntimeException("Your environment or operation system isn't supported");
}
What is the difference between these two methods? Is one more reliable than the other?
Note: I'm using PHP in the CLI, so it's always the actual current user running PHP.
EDIT> I understand that this question seems to ask for an opinion, but it's not the case. I DO NOT KNOW Windows and do not understand why some packages use different ways to determine the user's home directory. I'm asking for explanations about the two mentioned methods: is one of them more reliable than the other and why?
I've edited the title and the question to reflect this precision.
After not working on this for a long time, I finally decided to definitely answer this question.
There are some usefull environment variables defined on Windows: USERPROFILE, APPDATA, LOCALAPPDATA. They are easily accessible via getenv() function:
getenv('USERPROFILE');
USERPROFILE exists on any Windows, according to https://learn.microsoft.com/fr-fr/windows/desktop/shell/knownfolderid
So, on Windows, it seems to be reliable.
If you need to store data for the current user, APPDATA and LOCALAPPDATA are good variables to find that place.
I've written a package to make these tools reusable: https://github.com/Arcesilas/Platform
It's still work in progress and certainly needs to be improved. Any help is welcome to make this tool reliable on any platform.
Thanks to eryksun whose comments helped a lot in solving this question.
So I am using Less PHP to compile .less files down to .css and I decided to try out a small class I wrote where I take all the .less files in a directory and compile them to .css and move them to their own css directory.
So to test this I took all of twitter bootstrap less and placed it into a directory and then ran my class I wrote, see below, and found less php to be exploding: the current error is:
Error occurred:exception 'Exception' with message 'variable #alert-padding is undefined: failed at 'padding: #alert-padding;'
The class I wrote is just a simple wrapper:
class AisisLess_Less_Less{
protected $_less = null;
protected $_file = null;
public function __construct(){
$this->_file = new AisisCore_FileHandling_File();
$this->_less = new lessc();
$this->init();
}
public function init(){}
public function compile_directory($pattern, $compile_to_dir){
$less_files = $this->_file->get_directory_of_files($pattern);
$this->_compile($less_files, $compile_to_dir);
}
protected function _compile($array_of_files, $compile_directory){
foreach($array_of_files as $file){
$file_without_path = substr( $file, strrpos( $file, '/' )+1 );
try{
$css_file = preg_replace('"\.less"', '.css', $file_without_path);
$this->_less->checkedCompile($file, $compile_directory . $css_file);
}catch(exception $e){
throw new AisisLess_Exceptions_LessException('Error occurred:' . $e);
}
}
}
}
The concept is you use as such:
$less = new AisisLess_Less_Less();
$less->compile_directory(path/to/less/*.less, path/to/compiled/out/put);
My code is just a simple wrapper. The actual error is being thrown by the less library on some variable thing which is apart of the bootstrap less files.
So is the library acting up or is bootstrap failing at coding or have I screwed something up?
And if so how do I fix this?
What I suspect (no proof). If I understand you correctly, you just have the directory of bootstrap files and your code runs through them sequentially compiling them to css. That means the first file it is trying to compile is alerts.less which, low and behold, the very first variable reference in that file is (as of this writing) on line 10:
padding: #alert-padding;
This matches your error.
The issue is most likely that the bootstrap files are not designed to just be blindly compiled, because in most cases each is its own little piece, but requires other key pieces to compile (like variables.less and mixins.less). This is why, generally speaking, you only compile the bootstrap.less file which then will #import all the necessary files.
Basically, if I understand correctly what you have designed and how it works, you picked a bad set of files to run tests on because they are not designed to work that way. Better to just create a few small less files that are independent of each other for testing. However, what this has revealed is that your plan has a potential flaw, in that it will only function on standalone files, so you cannot blindly run any .less file through it, or you will get such compile errors because of broken dependencies.
I've been developing a custom CMS using Codeigniter locally and I've just gotten to the point where I need to upload it to a staging server to do some more testing.
Everything works except for the sidebar section of the site that uses a widget system. I initially thought it was just differences between PHP versions, as I am running 5.4.4 locally and the server was 5.3. After upgrading the server to 5.4.7, the sidebar is still not appearing. I get no error, just nothing displays.
This is the Widget library code:
<?php
if (!defined('BASEPATH')) exit('No direct script access allowed');
class Widgets {
private $_ci;
protected $parser_enable = FALSE;
public function __construct() {
$this->widgets();
}
public function widgets(){
$this->_ci =& get_instance();
}
public function build($view,$data=array()){
$view = get_class($this).'/'.$view;
$subdir = '';
if (strpos($view, '/') !== FALSE)
{
// explode the path so we can separate the filename from the path
$x = explode('/', $view);
// Reset the $class variable now that we know the actual filename
$view = end($x);
// Kill the filename from the array
unset($x[count($x)-1]);
// Glue the path back together, sans filename
$subdir = implode($x, '/').'/';
}
$widget_view = APPPATH.'widgets/'.$subdir.'views/'.$view.EXT;
if(file_exists($widget_view)){
$widget_view = '../widgets/'.$subdir.'views/'.$view.EXT;
if($this->parser_enable){
$this->_ci->load->library('parser');
return $this->_ci->parser->parse($widget_view,$data,TRUE);
}
else{
return $this->_ci->load->view($widget_view,$data,TRUE);
}
}
return FALSE;
}
public function __get($var) {
static $ci;
isset($ci) OR $ci = get_instance();
return $ci->$var;
}
}
Does anything jump out that could cause it not to display?
Is there anything I should be looking at to make it compatible, such as server modules? What on the server could be affecting this?
EDIT:
I have the widgets residing in the following path:
/public_html/application/widgets/recent_news/views/view.php
The $widget_view = 'widgets/'.$subdir.'views/'.$view.EXT; variable is returning widgets/Recent_news/views/view.php which is getting passed to:
if(file_exists($widget_view)){
return $this->_ci->load->view($widget_view,$data,TRUE);
}
The application path in $widget_view doesn't seem to be correct on the staging server, so file_exists() returns false and doesn't load the view (which would have an incorrect path anyways).
I just can't seem to make it read the correct path, any suggestions?
If it's a staging server, go into the php.ini file and set
error_reporting = E_ALL | E_STRICT
display_errors = On
This will output whatever errors it finds so you can debug it.
Ended up just needing to subdir = strtolower($subdir);
Thanks for the help everyone
I have just started out with testing some php mvc framework
In it, it has this function that throws an error.
The cachedirectory is set to /tmp/cache from the config file
additional:
The php is hosted on an IIS server.
Can someone help me out to get this working somehow?
This is the function within the class
function setCacheDir($cacheDir = null)
{
if( is_null( $cacheDir ) )
{
$config = config::getInstance();
$cacheDir = $config->config_values['template']['cache_dir'];
}
if (is_dir($cacheDir) && is_writable($cacheDir))
{
$config = config::getInstance();
$this->cache_dir = $cacheDir;
}
else
{
throw new Exception("De cache directory '$cacheDir' either does not exist, or is unwriteble");
}
}
thanks, Richard
Why don't you set the cache directory to something a little more Windows-y, like c:\temp (and make sure that folder exists).
I'm guessing "/tmp/cache" doesn't exist and isn't writable, so in the configuration file, set cache_dir to a directory that is.
Some PHP frameworks work best (or better) in a LAMP stack, the first letter (L) being Linux. If the documentation of your framework advises a LAMP stack, I'd go with that.
I want to execute a php-script from php that will use different constants and different versions of classes that are already defined.
Is there a sandbox php_module where i could just:
sandbox('script.php'); // run in a new php environment
instead of
include('script.php'); // run in the same environment
Or is proc_open() the only option?
PS: The script isn't accessible through the web, so fopen('http://host/script.php') is not an option.
There is runkit, but you may find it simpler to just call the script over the command line (Use shell_exec), if you don't need any interaction between the master and child processes.
The is a class on GitHub that may help, early stages but looks promising.
https://github.com/fregster/PHPSandbox
Also, you should look at the backtick operator:
$sOutput = `php script_to_run.php`;
This will allow you to inspect the output from the script you are running. However, note that the script will be run with the privileges you have, but you can circumvent this by using sudo on Linux.
This approach also assumes that you have the PHP CLI installed, which is not always the case.
There is Runkit_Sandbox - you might get it to work, it's a PHP extension. I'd say the way to go.
But you might need to create a "sandbox" your own, e.g. by resetting the global variable state of the superglobals you use.
class SandboxState
{
private $members = array('_GET', '_POST');
private $store = array();
public function save() {
foreach($members as $name) {
$this->store[$name] = $$name;
$$name = NULL;
}
}
public function restore() {
foreach($members as $name) {
$$name = $this->store[$name];
$this->store[$name] = NULL;
}
}
}
Usage:
$state = new SanddboxState();
$state->save();
// compile your get/post request by setting the superglobals
$_POST['submit'] = 'submit';
...
// execute your script:
$exec = function() {
include(func_get_arg(0)));
};
$exec('script.php');
// check the outcome.
...
// restore your own global state:
$state->restore();
dynamic plugin function execution that allows the loaded file and function to execute anything it wants, however it can only take and return variables that can be json_encode'ed.
function proxyExternalFunction($fileName, $functionName, $args, $setupStatements = '') {
$output = array();
$command = $setupStatements.";include('".addslashes($fileName)."');echo json_encode(".$functionName."(";
foreach ($args as $arg) {
$command .= "json_decode('".json_encode($arg)."',true),";
}
if (count($args) > 0) {
$command[strlen($command)-1] = ")";//end of $functionName
}
$command .= ");";//end of json_encode
$command = "php -r ".escapeshellarg($command);
exec($command, $output);
$output = json_decode($output,true);
}
the external code is totally sandboxed and you can apply any permission restrictions you want by doing sudo -u restricedUser php -r ....
I have developed a BSD-licensed sandbox class for this very purpose. It utilizes the PHPParser library to analyze the sandboxed code, check it against user-configurable whitelists and blacklists, and features a wide array of configuration options along with sane default settings. For your needs you can easily redefine classes called in your sandboxed code and route them to different ones.
The project also includes a sandbox toolkit (use only on your local machine!) that can be used to experiment with the sandbox settings, and a full manual and API documentation.
https://github.com/fieryprophet/php-sandbox
i know its not 100% topic related, but maybe useful for somebody n__n
function require_sandbox($__file,$__params=null,$__output=true) {
/* original from http://stackoverflow.com/a/3850454/209797 */
if($__params and is_array($__params))
extract($__params);
ob_start();
$__returned=require $__file;
$__contents=ob_get_contents();
ob_end_clean();
if($__output)
echo $__contents;
else
return $__returned;
};