Reputation: 527
I am very much aware that PHP is a server side language and therefore should not allow the php file to be downloaded. However, on direct visit in Chrome to the PHP file, it downloads an obfuscated version of the file, something I'd like to prevent. Is there a way to stop the file from being served up?
The code is below.
The system works to perfection inside WordPress, but if I open up Chrome (and I presume others) and visit the update.php file directly, it downloads.
Notably, I tried to echo an HTML page but it messes up the way the system works. I'm hoping there's some sort of .htaccess trick for this.
if (isset($_POST['action'])) {
switch ($_POST['action']) {
case 'version':
echo '1.1';
break;
case 'info':
$obj = new stdClass();
$obj->slug = 'plugin.php';
$obj->plugin_name = 'plugin.php';
$obj->new_version = '1.1';
$obj->requires = '3.0';
$obj->tested = '3.3.1';
$obj->downloaded = 12540;
$obj->last_updated = '2012-01-12';
$obj->sections = array(
'description' => 'The new version of the Auto-Update plugin',
'another_section' => 'This is another section',
'changelog' => 'Some new features'
);
$obj->download_link = 'http://localhost/update.php';
echo serialize($obj);
case 'license':
echo 'false';
break;
}
} else {
header('Cache-Control: public');
header('Content-Description: File Transfer');
header('Content-Type: application/zip');
readfile('update.zip');
}
Upvotes: 0
Views: 746
Reputation: 4879
You set the content type to application/zip which in most browsers prompts a download. Is there a chance that you're not passing an "action" via POST and that is why it's hitting that else section?
One more thing I see is you have no
break;
In your second switch/case.
$obj->download_link = 'http://localhost/update.php';
echo serialize($obj);
break; // <------ this is missing!
case 'license':
echo 'false';
break;
Have you checked out this article: http://konstruktors.com/blog/wordpress/2538-automatic-updates-for-plugins-and-themes-hosted-outside-wordpress-extend/
Regarding restricting access to the file to everyone except WordPress, it's unknown if you host your WordPress site or not. If you do, you could restrict access to localhost or 127.0.0.1 in your .htaccess file. If it's hosted on WordPress.com you find their IP or hostname and change it.
<Files update.php>
Order allow,deny
Deny from all
Allow from 127.0.0.1
</Files>
Upvotes: 0
Reputation: 270607
Your code, if it does not receive $_POST['action']
, then sends update.zip
to the browser in the else
case.
What you are seeing when visit the file not via a POST is not obfuscated PHP. Rather, it is sending the contents of the file update.zip
to the browser for download. But since the code doesn't supply a filename hint in the headers, it doesn't come as update.zip
and instead probably looks like a .php file with the same name as your script.
If you want update.zip
to look like a zip file, add a filename
into the Content-Disposition
output header:
header('Cache-Control: public');
header('Content-Description: File Transfer');
// Change to attachment disposition, with filename
header('Content-Disposition: attachment; filename=update.zip');
header('Content-Type: application/zip');
readfile('update.zip');
Now, if you don't want it sending update.zip
at all, remove the entire else {}
block from the bottom, and replace it with something like
else {
echo "You must supply an action...";
}
wp_autoupdate.php
Consult $_SERVER['HTTP_REFERRER']
, but know that the value of this can be spoofed. This cannot be used with 100% reliability.
if (strpos($_SERVER['HTTP_REFERER'], 'wp_autoupdate.php') !== FALSE) {
// Include all your exsiting code
}
else {
// Don't do anything, or redirect somewhere else
header("Location: /");
exit();
}
To achieve 100% reliability, you would probably need to modify wp_autoupdate.php
to set a session variable which is then checked by update.php
, ensuring the request came from the right place.
Upvotes: 1