PHP script to check on remote server, a file exists - php

I am having roblems with locating a PHP script to allow me to obtain the contents of a txt file on a remote server, then output to a variable. Outputting something to a variable is not the hard part. It's the picking up and reading the contents of the file that's the hard part. Anyone have any ideas?
I have trawled the forum and can only locate a method that works locally. Not ideal as the target is remote.
The objective really is, how do I find out if a file exists on the remote server and output a status in html.
Ideas?

Assuming your remote server is accessible by http or ftp you can use file_exists():
if (file_exists("http://www.example.com/somefile.txt")) {
echo "Found it!;
}
or
if (file_exists("ftp:user:password#www.example.com/somefile.txt")) {
echo "Found it!;
}

Use this:
$url = 'http://php.net';
$file_headers = #get_headers($url);
if($file_headers[0] == 'HTTP/1.1 404 Not Found') {
echo "URL does not exist";
}
else {
echo "URL exists";
}
Source: http://www.php.net/manual/en/function.file-exists.php#75064

You can try to use this code:
if (file_exists($path)) {
echo "it exists";
} else {
echo "it does not exist";
}
As you can see $path is the path of your file. Of course you can write anything else instead of those echo.

Accessing files on other servers can be quite tricky! If you have access to the file via ftp, you can use ftp to fetch the file, for example with ftp_fget().
If you do not have access to the file-system via ssh, you only can check the response the server gives when requesting the file. If the server responds with an error 404, the file is either not existent or it is not accessible via http due to the server configuration.
You can check this through curl, see this tutorial for a detailled explanation of obtaining the response code through curl.

I know this is an old thread, but as Lars Ebert points out, checking for the existence of a file on a remote server can be tricky, so checking the server response, using cURL, is how I have been able to do it on our big travel site. Using file_exists() threw an error every time, but checking for a "200 OK" has proved quite successful. Here is the code we are using to check for images for our hotel listings page:
$media_url = curl_init("http://pathto/remote_file.png");
curl_setopt($media_url, CURLOPT_RETURNTRANSFER, true);
$media_img = curl_exec($media_url);
$server_response = curl_getinfo($media_url, CURLINFO_HTTP_CODE);
if($server_response != 200){
echo "pathto/graphics/backup_image.png";
}else{
echo "http://pathto/remote_file.png";
}
Where "http://pathto/remote_file.png" is the remote image we seek, but we need to know whether it is really there. And "pathto/graphics/backup_image.png" is what we display if the remote image does not exist.
I know it's awfully verbose, compared to file_exists(), but it's also more accurate, at least so far.

Related

Setting up ESP8266httpUpdate server with Node-Red

Apologies in advance for any mistakes as I'm very new to Node-Red. I'm trying to set up a simple HTTP server to update my ESP8266 node.
How it works is: the ESP8266 will send an HTTP request to a specific URL, and await a response of a binary folder. The binary file is stored in a folder locally on my Windows PC where the Node-Red is running. How can I setup a Node-Red flow that will do this?
This is my current setup but it doesn't work. When I request the URL through a web browser, it just downloads a folder with no file type.
These are the documentations for the ESP8266 side. The documentation recommends to setup a PHP server with the following code. However, this code is a little more complex which helps check the version before updating with the right binary file which I plan to implement later on in Node-Red.
header('Content-type: text/plain; charset=utf8', true);
function check_header($name, $value = false) {
if(!isset($_SERVER[$name])) {
return false;
}
if($value && $_SERVER[$name] != $value) {
return false;
}
return true;
}
function sendFile($path) {
header($_SERVER["SERVER_PROTOCOL"].' 200 OK', true, 200);
header('Content-Type: application/octet-stream', true);
header('Content-Disposition: attachment; filename='.basename($path));
header('Content-Length: '.filesize($path), true);
header('x-MD5: '.md5_file($path), true);
readfile($path);
}
if(!check_header('HTTP_USER_AGENT', 'ESP8266-http-Update')) {
header($_SERVER["SERVER_PROTOCOL"].' 403 Forbidden', true, 403);
echo "only for ESP8266 updater!\n";
exit();
}
if(
!check_header('HTTP_X_ESP8266_STA_MAC') ||
!check_header('HTTP_X_ESP8266_AP_MAC') ||
!check_header('HTTP_X_ESP8266_FREE_SPACE') ||
!check_header('HTTP_X_ESP8266_SKETCH_SIZE') ||
!check_header('HTTP_X_ESP8266_CHIP_SIZE') ||
!check_header('HTTP_X_ESP8266_SDK_VERSION') ||
!check_header('HTTP_X_ESP8266_VERSION')
) {
header($_SERVER["SERVER_PROTOCOL"].' 403 Forbidden', true, 403);
echo "only for ESP8266 updater! (header)\n";
exit();
}
$db = array(
"18:FE:AA:AA:AA:AA" => "DOOR-7-g14f53a19",
"18:FE:AA:AA:AA:BB" => "TEMP-1.0.0"
);
if(isset($db[$_SERVER['HTTP_X_ESP8266_STA_MAC']])) {
if($db[$_SERVER['HTTP_X_ESP8266_STA_MAC']] !=
$_SERVER['HTTP_X_ESP8266_VERSION']) ) {
sendFile("./bin/".$db[$_SERVER['HTTP_X_ESP8266_STA_MAC']]."bin");
} else {
header($_SERVER["SERVER_PROTOCOL"].' 304 Not Modified', true, 304);
}
exit();
}
header($_SERVER["SERVER_PROTOCOL"].' 500 no version for ESP MAC', true,
500);
Any help will be much appreciated. Thank you.
First things first. Let´s try to understand why your flow does not work and try to have it fixed.
There is a flow in Node-RED library that performs exactly what you want to achieve. If you have not tried yet please do it asap.
Link: https://cookbook.nodered.org/http/serve-a-local-file
Second point to consider: When we want to serve local content we need to set up an http static path in Node-RED configuration file called: settings.js
You have to open this file, find the line that start with httpStatic:, modify it to your fit your setup and leave it uncommented. Here is how my setup looks like (don´t simply copy and paste, you need to configure your directory here).
// following property can be used to identify a directory of static content
// that should be served at http://localhost:1880/.
//httpStatic: '/home/nol/node-red-static/',
httpStatic: "C://Users/OCM/.node-red/static",
Be careful when selecting the file to edit. According to the words of the experts:
"Most often, when your changes to the settings file are not taking effect, it means you have edited the wrong file. There is one delivered with the installed code, which is then copied into your user directory (typically ~/.node-red). Rickus"
Finally, don´t forget to copy your binary file to this static directory.
After checking all those points it is likely that the outcome of your flow will be the binary file and this can be checked by adding a debug node (configured to display complete msg object) right after the file in node. If you see a buffer in your msg.payload it means that your flow is serving the binary file.
EDIT: Searching Node-RED library I see that there is already an example flow that is compliant with ESP8266httpUpdate HTTP requests.
Link: https://flows.nodered.org/flow/888b4cd95250197eb429b2f40d188185

best way to check if xml (without file extension) exists

Unfortunately I can't check it right now, because the XML (which will be on another server) is offline. The url to the xml file will look like this: http://url.com:123/category?foo=bar. It comes with no .xml file extension as you can see. I forgot to insert a file check to avoid error messages printing out the url of the xml file.
simple_load_file works fine with that URL, but I'm not sure about file_exists!
Would this work?:
if(file_exists('http://url.com:123/category?foo=bar')) {
$xml = simplexml_load_file('http://url.com:123/category?foo=bar');
//stuff happens here
} else{echo 'Error message';}
I'm not sure since file_exists doesn't work with URLs.
Thank you!
As you suspect, file_exists() doesn't work with URLs, but fopen() and fclose() do:
if (fclose(fopen("http://url.com:123/category?foo=bar", "r"))) {
$xml = simplexml_load_file('http://url.com:123/category?foo=bar');
//stuff happens here
} else {
echo 'Error message';
}
It is not really useful, if you just try to fetch the data to parse it. Especially if the URL you call is a program/script itself. This will just mean that the script is executed twice.
I suggest you fetch the data with file_get_contents(), handle/catch the errors and parse the fetched data.
Just blocking the errors:
if ($xml = #file_get_contents($url)) {
$element = new SimpleXMLElement($xml);
...
}

PHP file_get_contents returns "1" and fails with request headers

I have a php file fopen.php that retrieves data from another php file d.php with a GET request e.g. d.php?p=4
When I run this code I'm getting weird results. It works on my local server but not on the heartinternet one that this website is running on
fopen.php?p=4
echo $_GET['p']."<br/>";
if (!file_exists("d.php")) {
die('File does not exist');
}
else
{
echo file_get_contents("d.php") or die("FAIL");
echo "<br/>";
echo file_get_contents(("d.php?p=".$_GET['p'])) or die("FAIL");
}
This page reads as follows:
4
1
FAIL
allow_url_fopen is On
Any clues as to what might be happening?
You need to specify the full URL (including http://) if you want to initiate a GET request with file_get_contents.
By requesting d.php?p=4, you're supposed using HTTP(s) request, so It's required a full URL. It's weird that your code working in local server.
Btw, you may using it wrong, any HTTP request should be used for connecting to external resource, in this case, you just need some kind of local including.
Ex:
else
{
//echo file_get_contents("d.php") or die("FAIL");
//echo "<br/>";
//echo file_get_contents(("d.php?p=".$_GET['p'])) or die("FAIL");
$p = $_GET['p'];
include 'd.php';
}
And on your d.php, instead of extracting $_GET['p'], you can directly use the $p variable declared on the above code block

Delete file from second server via first server via php

I have two servers. I want delete file from second server via first server!
For example:
first-server.com
second-server.com
I have made two php files - file on first server and file on second server.
The file on first server contains
files.php
while($file = mysql_fetch_array($files){
echo $file['file_name'];
echo 'Delete';
}
the file on second server contains
delete.php
if($_GET['file']){
if(file_exists($_GET['file']){
unlink($_GET['file'];
//file deleted !
}
No it's ok , but. I want done this job without redirect me or visitor to the second server
For example : ajax or curl or something like that. What is the best way to do that?
Edit.
The codes above is just tests. It's not my real files. Please help in the way to process delete request without redirect to second server php file.
I think a simple file_get_contents is enough:
File on first server:
$result = file_get_contents('second-sercer.com/delete.php?file=text.txt&some_security_token=asd');
//From $result you will know what was the result on the other server
File on second server (delete.php);
if($_GET['some_security_token'] == "asd"){
if(file_exists($_GET['file']){
if(unlink($_GET['file'])){
//File deleted we are cool
echo 1;
} else {
//File deletion failed
echo 0;
}
}else{
//File don't exists
echo -1;
}
}else{
//bad token
echo -2;
}
So this way your first server on script level goes to the second server so you can check parameters before that. And the second server sends back error / success codes so you can handle them on first server:
1 - success
0 - failed deletion
-1 - file doesn't even exists
-2 - bad security token
I do not include a way to create a token that both of the servers know. You can hash the file name with some key value for start, but you have to make it expensive to guess. I just try to point out that you need this kind of security too to make it even safer. And you have to find out a way to protect file system from deleting files that important for second-server. For example you only let the deletion of files in some folder only.
You could use cURl too the same way for this. But always try to return info for the first-server.com about the process on the second-server.com
unset unsets a variable, it doesn't have anything to do with files.
You're looking for unlink.
BTW, you should do some serious validation on what you're going to unlink. Just blindly accepting anything in the URL can have serious consequences.
http://second_server.com/delete.php?file=delete.php
Delete file
<?php if ($foo = $_GET['file']) {
echo "<img src=\"http://second_server.com/delete.php?file=$foo\" style=\"display:none;\"><script>alert('deleted');</script>"; }
?>
First of all, you want a security code or token or the like, so that unauthorised people do not delete files from your server.
while($file = mysql_fetch_array($files){
echo $file['file_name'];
echo 'Delete';
}
and in first_server.com/delete.php, put this:
file_get_contents('second-server.com/delete.php?file=' . $_GET['file'] . '&securitycode=thisisasecuritycode');

weird problem with file_get_contents and twitter

I made this function to verify a user's twitter credentials. Its running on two different webservers.
<?
function twitauth($username, $password){
if(#file_get_contents("http://".$username.":".$password."#twitter.com//account/verify_credentials.xml")){
return "1";}
else {
return "0";}
}
?>
On my webserver, it works fine. On the other one, it ALWAYS returns 1! Even when password is intentionally wrong.
What in the world would cause one server to do one thing, and the other to do something else?
When I visit that url with any combination of username/password it always returns something, whether it's auth successful or failure. file_get_contents() only returns FALSE when it fails to open the requested url.
It seems to me for your function to be successful you would have to parse the return value to determine whether or not the auth was successful.
Remove the '#' sign from the function to see the error message (if there is one).
Some PHP configurations don't allow opening files over the HTTP protocol, so look into cURL, or try looking up the official Twitter API to see if they have authentication functions for you to use.
I came up with an alternative solution.
<?
function twitauth($username, $password){
$xml = #simplexml_load_file("http://".$username.":".$password."#twitter.com/statuses/friends_timeline.xml");
$noway = $xml->error;
$errorcheck = "Could not authenticate you.";
if($noway == $errorcheck){
return "0";
} else {
return "1";
}
}
?>
The # symbol (error suppression) in front of file_get_contents might be suppressing an error. Try removing it and see what error you get. Also, you might be seeing different behavior on different servers due to php configuration. Specifically, the allow_url_fopen setting changes file_get_contents ability to work with URLs. Check this setting on both servers (maybe with ini_get() or find the setting in the output of phpinfo().
Here is an updated response that isn't returning booleans as strings, and it's weird to check if its the error message before checking if its not the error message.
<?php
function twitauth($username, $password){
$xml = #simplexml_load_file("http://". urlencode($username) .":". urlencode($password) ."#twitter.com/statuses/friends_timeline.xml");
return ($xml->error != "Could not authenticate you.") ? true : false;
}
?>
file_get_contents() will only return the response of the page, which can be an authenticated user or a bad response, you need to use SimpleXML or what not to parse the response to determine whether or not they were authenticated. Which looks like:
<?xml version="1.0" encoding="UTF-8"?>
<user>
<id>800316</id>
<name>Garrett</name>
<screen_name>garrettb</screen_name>
<location>WHER>!, CA, USA</location>
<description>Build websites, wants to be rich, and loves my Mac. You?</description>
<profile_image_url>http://a1.twimg.com/profile_images/185221952/pic_normal.png</profile_image_url>
<url></url>
<protected>false</protected>
<followers_count>158</followers_count>
<profile_background_color>352726</profile_background_color>
<profile_text_color>3E4415</profile_text_color>
<profile_link_color>D02B55</profile_link_color>
<profile_sidebar_fill_color>99CC33</profile_sidebar_fill_color>
<profile_sidebar_border_color>829D5E</profile_sidebar_border_color>
<friends_count>139</friends_count>
<created_at>Wed Feb 28 06:03:17 +0000 2007</created_at>
<favourites_count>18</favourites_count>
<utc_offset>-28800</utc_offset>
<time_zone>Pacific Time (US & Canada)</time_zone>
<profile_background_image_url>http://s.twimg.com/a/1251845223/images/themes/theme5/bg.gif</profile_background_image_url>
<profile_background_tile>false</profile_background_tile>
<statuses_count>1781</statuses_count>
<notifications></notifications>
<verified>false</verified>
<following></following>
<status>
<created_at>Wed Sep 02 19:07:59 +0000 2009</created_at>
<id>3716655439</id>
<text>#lucaspatton09 take a picture, I want to see.</text>
<source><a href="http://www.atebits.com/" rel="nofollow">Tweetie</a></source>
<truncated>false</truncated>
<in_reply_to_status_id>3716512637</in_reply_to_status_id>
<in_reply_to_user_id>59230940</in_reply_to_user_id>
<favorited>false</favorited>
<in_reply_to_screen_name>lucaspatton09</in_reply_to_screen_name>
</status>
</user>
If the request is denied (bad access), it will have a authentication dialog drop down, which is probably causing you problems.
file_get_contents usually gives warning and returns nothing upon encountering http error code, but in case of your other server it probably returns body of error page (maybe it can be set up by some configuration).
Code below should work for both cases:
if(strpos(
#file_get_contents("http://".$username.":".$password."#twitter.com//account/verify_credentials.xml"),
"Could not authenticate you.") === false) {
echo "credentials ok";
} else {
echo "credentials not ok";
}

Categories