php file() triggers no Exception on valid URL - file

try {
$antwort = file_get_contents('http://not_existing.notnotnot', false);
if($antwort===false) echo 'ERROR';
} catch(Exception $e) {
$e->getMessage();
}
var_dump($antwort); // returns string(0) ""
I get no Exception, no false, just empty content for every URL. A valid URL returns with this snippet the right content. Why can't I get exceptions for an invalid URL?
I came to this question because a wget on the same server leads to a valid return, but with a php script I can't file() the same URL. Really weird and I have no idea how to debug it.

It won't throw an exception if the file isn't found; it will raise a warning-level error. Those are different things. From the docs:
An E_WARNING level error is generated if filename cannot be found, maxlength is less than zero, or if seeking to the specified offset in the stream fails.
You should check for a false return, as you do, and not expect to catch an exception.
Also keep in mind when fetching a URL that the remote server may return an incorrect status code (instead of the expected 404), causing your script to think the file exists when it does not. You may need to check for empty values ("") as well.
As a rule, you should avoid using file_get_contents to access files via HTTP. It's not terribly secure, and many hosts don't even allow you to use it that way. Instead, use cURL, which is specifically designed for retrieving data over the web, including via HTTP.

Related

Would an IndexBatch operation with a single document ever throw IndexBatchException?

The IndexBatchException documentation, e.g., when calling IndexAsync, states:
Thrown when some of the indexing actions failed, but other actions succeeded and modified the state of the index. This can happen when the Search Service is under heavy indexing load. It is important to explicitly catch this exception and check its IndexResult property. This property reports the status of each indexing action in the batch, making it possible to determine the state of the index after a partial failure.
Does this mean this exception can be safely ignored when there is just a single document in the IndexBatch? Since, it seems impossible for an IndexBatch with just a single document to fail partially.
I tried calling IndexAsync with a Merge batch containing a single document to update, but with a non-existing document key (as recommended by Bruce):
var nonExistingDocument = SomeDocument()
var work = IndexBatch.Merge( nonExistingDocument );
try
{
await _search.Documents.IndexAsync( work );
}
catch ( IndexBatchException e )
{
var toRetry = e.FindFailedActionsToRetry( work, d => d.Id);
}
IndexBatchException was triggered, which is different behavior than what is documented in two ways:
"Thrown when some of the indexing actions failed, but other actions succeeded and modified the state of the index." Instead, the exception is thrown when any action fails.
"This can happen when the Search Service is under heavy indexing load." This can also happen for incorrect requests.
But, FindFailedActionsToRetry is seemingly smart enough to not suggest retrying requests which have failed due to erroneous requests. The toRetry enumeration is empty in the code sample above.
In short, no, this exception cannot be safely ignored. The documentation is misleading and it would be nice if it were updated.

Spontaneous Server Errors During AngularJS $http calls

I'm building an SPA in AngularJS served by a Laravel (5.1) backend. Of late I've been encountering an annoying error, a server 500 or code 0 error which is abit hard to explain how it comes but let me try to may be someone will understand the dental formula of my problem.
When i start my AngularJS controller, I make several server calls (via independent $http calls from services) to retrieve information i might later need in the controller. For example,
Functions.getGrades()
.then(function(response)
{
$scope.grades = response.data;
});
Subjects.offered()
.then(function(response)
{
$scope.subjects = response.data;
});
Later on i pass these variables (grades or subjects) to a service where they are used for processing. However, these functions are randomly returning code 500 server errors after they run, and sometimes returning status code 0 after running. This happens in a random way and it is hard for me to point out the circumstances leading to their popping up. This leaves me with frequent empty Laravel-ised error screens like the ones shown below.
Anyone reading my mind?
Ok, after a suggestion given in a comment above that I check my Laravel log files (located in storage/logs/laravel.log- Laravel 5.1), i found out that the main error most of these times was this one: 'PDOException' with message 'SQLSTATE[HY000] [1044] Access denied for user ''#'localhost' to database 'forge'' in ..., plus another one that paraphrased something like No valid encrypter found. These were the key opener.
On reading another SO thread here, it said in part:
I solved, sometimes laravel not read APP_KEY in .ENV. And returns a value "SomeRandomString" (default is defined in config / app.php), and have the error "key length is invalid", so the solution is to copy the value of APP_KEY, to the value 'key 'in config / app.php, that's all! I solved!
That was exactly the issue! When loading the DB params from the .env to config/database.php, Laravel was sometimes unable to read the environment variables and went for the fallback default fallback options (forge for DB name and username and SomeRandomString for the APP_KEY). So, to solve this i just did as advised: copied the APP_KEY in .env to the config/app.php and edited the default DB parameters to the actual DB name and username/password I'm using. Just that and i was free from pollution. Hope someone finds this helpful.

CakePHP ini_set on Shared Host

I'm on a shared host and ini_set function is disabled for security reasons. I'm trying to deploy CakePHP 2.4.1 on this host. Fresh cake installation results in a blank page, with no errors shown, instead if I comment these lines:
\lib\Cake\Model\Datasource\CakeSession.php
if (empty($_SESSION)) {
if (!empty($sessionConfig['ini']) && is_array($sessionConfig['ini'])) {
foreach ($sessionConfig['ini'] as $setting => $value) {
if (ini_set($setting, $value) === false) {
throw new CakeSessionException(__d('cake_dev', 'Unable to configure the session, setting %s failed.', $setting));
}
}
}
}
Everything seems to works fine. Now, I'm asking what is the downside of keeping that snippets commented (in other word, what is that code responsible for)?
As the exception message, the method name and the rest of the code indicates, it configures the session settings, session name, cookie lifetime, save handler, etc...
Your code may run fine, and you should be able to use the PHP session_*() functions instead to configure the settings (the best place for that would probably your bootstrap.php). Also writing a dummy value into $_SESSION seems to prevent the CakeSession::_configureSession() to use ini_set(), so you don't have to modify it.
So this might work, but it shouldn't be necessary to jump through such hoops. There's no need to disable ini_set() in a properly set up shared hosting environment, and personally I'd change the hoster in case they are unable to change this behaviour.

store all the errors occurred on eval() in PHP

Stack community.
I'm using the eval() function in PHP so my users can execute his own code in my website (Yes, i know it is a dangerous function, but that's not the point).
I want to store all the PHP errors that occur during the interpretation of the code, is there a way to fetch all of them? i want to get and register them in a table of my database.
The error_get_last gets only the last error, but i want all of them.
Help me, please. It is even possible?
General
You cannot use eval() for this, as the evaled code will run in the current context, meaning that the evaled code can overwrite all vars in your context. Beside from security considerations this could / would break functionality. Check this imaginal example:
$mode = 'execute'
// here comes a common code example, it will overwrite `$mode`
eval('
$mode = 'test';
if(....) { ...
');
// here comes your code again, will fail
switch ( $mode) {
...
}
Error Tracking
You cannot track the errors this way. One method would be to use set_error_handler() to register a custom error handler which stores the errors to db. This would work, but what if the user uses the function in it's code? Check the following examples:
set_error_handler('my_handler');
function my_handler($errno, $errstr, $errfile, $errline) {
db_save($errstr, ...);
}
eval('
$a = 1 / 0; // will trigger a warning
echo $b; // variable not defined
'
);
This would work. But problems will arise if have an evaled code like this:
eval('
restore_error_handler();
$a = 1 / 0; // will trigger a warning
echo $b; // variable not defined
'
);
Solution
A common solution to make it possible that others can execute code on your servers is:
store user code into temporary file
disable critical functions like fopen() ... in the php.ini
execute the temporary php file by php-cli and display output (and errors) to the user
if you separate stdin from stdout when calling the php-cli, you can parse the error messages and store them in a DB
According to the documentation, you just can't :
If there is a parse error in the evaluated code, eval() returns FALSE and execution of the following code continues normally. It is not possible to catch a parse error in eval() using set_error_handler().
EDIT: you can't do it with eval(), but you apparently can with php_check_syntax function. You have to write the code to a file in order to check its syntax.

Setting the header to be content image in CakePHP

I am writing an action in a controller where in a certain case, I want to output raw image data directly, and want to set the header content-type appropriate. However I think the header is already being set earlier by CakePHP (I am setting render to be false).
Is there a way to get around this? Thanks!
As said before, CakePHP does not send headers when render is false. Beware though, that any code doing an 'echo' will send headers (except you are using output-buffering). This includes messages from PHP (warnings etc.).
Sending the file can be done in numerous ways, but there are two basic ways:
Send the file using plain PHP
function send_file_using_plain_php($filename) {
// Avoids hard to understand error-messages
if (!file_exists($filename)) {
throw RuntimeException("File $filename not found");
}
$fileinfo = new finfo(FILEINFO_MIME);
$mime_type = $fileinfo->file($filename);
// The function above also returns the charset, if you don't want that:
$mime_type = reset(explode(";", $mime_type));
// gets last element of an array
header("Content-Type: $mime_type");
header("Content-Length: ".filesize($filename));
readfile($filename);
}
Use X-Sendfile and have the Webserver serve the file
// This was only tested with nginx
function send_file_using_x_sendfile($filename) {
// Avoids hard to understand error-messages
if (!file_exists($filename)) {
throw RuntimeException("File $filename not found");
}
$fileinfo = new finfo(FILEINFO_MIME);
$mime_type = $fileinfo->file($filename);
// The function above also returns the charset, if you don't want that:
$mime_type = reset(explode(";", $mime_type));
// gets last element of an array
header("Content-Type: $mime_type");
// The slash makes it absolute (to the document root of your server)
// For apache and lighttp use:
header("X-Sendfile: /$filename");
// or for nginx: header("X-Accel-Redirect: /$filename");
}
The first function occupies one PHP-process / thread while the data is being send and supports no Range-Requests or other advanced HTTP-features. This should therefore only be used with small files, or on very small sites.
Using X-Sendfile you get all that, but you need to know which webserver is running and maybe even a change to the configuration is needed. Especially when using lighttp or nginx this really pays off performance-wise, because these webservers are extremly good at serving static files from disk.
Both functions support files not in the document-root of the webserver. In nginx there are so called "internal locations" (http://wiki.nginx.org/HttpCoreModule#internal). These can be used with the X-Accel-Redirect-Header. Even rate-throtteling is possible, have a look at http://wiki.nginx.org/XSendfile.
If you use apache, there is mod_xsendfile, which implements the feature needed by the second function.
It's not $this->render(false), it's $this->autoRender=false; The header is not sent in the controller action unless you echo something out.
If render is false, cake will not send a header.
You can rely on plain ol' php here.
PNG:
header('Content-Type: image/gif');
readfile('path/to/myimage.gif');
JPEG:
header('Content-Type: image/jpeg');
readfile('path/to/myimage.jpg');
PNG:
header('Content-Type: image/png');
readfile('path/to/myimage.png');

Resources