Situation: I'm improving some code on a PHP based monitoring web app that checks the health of other web apps/services.
Goal: we are using CURL as a primary method to get headers to ensure the monitored app is accessible via HTTP return codes. This works great as of now. However, we are trying to build in a "fallback" method in which IF the CURL HTTP code response from the monitored app is outside of our defined variables (ie http code 404), PHP would then use a PING-like function to check if there is any response at that same address (for example, webserver is still "running" (occupying the given port) but not serving proper headers).
Problem: Our fallback method (stream_socket_client) DOES work for non-secure sites as we can simply define "hostname:port" which BOTH curl and stream_socket_client can use. However, If we want to monitor a secure site (HTTPS), curl requires the HTTPS protocol to be defined before the host - which will then make our fallback method (stream_socket_client) function fail as it only uses host:port format.
So, for example:
$URL: https://example.com:443 (this would turn a "GOOD" CURL response, but a down stream_socket_client response)
$URL: example.com:443 (this would return a "UP" stream_socket_client response, but a "DOWN" CURL response)
So, if we used https://example.com:443 as our URL, and the webserver became unresponsive, but is still running on that port, both would fail because HTTPs is defined.
This is a simplified version of our current code:
<?php
$url = "example.com:80";
function curl($url) {
$handle = curl_init($url);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($handle, CURLOPT_HEADER, true);
curl_setopt($handle, CURLOPT_NOBODY, true);
curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($handle, CURLOPT_URL, $url);
$response = curl_exec($handle);
$httpCode = curl_getinfo($handle, CURLINFO_HTTP_CODE);
if($httpCode >= 200 && $httpCode < 400 || $httpCode == 401 || $httpCode == 405) {
echo "CURL GOOD, $httpCode";
echo "STATUS: GREEN";
}
else {
$fp = stream_socket_client("$url", $errno, $errstr);
if (!$fp) {
echo "CURL BAD, PING DOWN";
echo "STATUS: RED";
}
else {
echo "CURL BAD PING UP";
echo "STATUS: YELLOW";
}
}
curl_close($handle);
};
?>
Any ideas how to use a fallback method to check if a port is open or not? I don't have to stick with PHP, can use some JS, but would prefer PHP.
EDIT 1:
Thanks to #drew010 I know I need to ultimately use fsockopen. However, I'll need to use parse_url() which can then pass a "sterile" URL to fsockopen for fallback "ping" check.
However, I'm not sure how to strip ONLY the protocol and leave the port and sub path (if defined). I'm also not sure how to pass the sterile URL to the fsockeopn function to use for the check. So far I have the code below, but I know I'm missing some code.
The below code parses http://example.com to example.com.
function parseurl($url) {
$url = 'http://example.com:80';
$host = parse_url($url, PHP_URL_HOST);
//this works for stripping protocol and "wwww" but need to leave port and sub path if defined.
if (!$host)
$host = $url;
if (substr($host, 0, 4) == "www.")
$host = substr($host, 4);
if (strlen($host) > 50)
$host = substr($host, 0, 47) . '...';
return $host;
}
// How to pass steril URL to PING function??
function ping($host, $timeout = 1) {
if (!fsockopen($host, $port, $errno, $errstr, $timeout)) {
return false;
echo "OPEN";
}
else {
echo "CLOSED";
}
}
Found the answer:
This script uses CURL to check if given HOST is serving a webpage.
If NOT, use a PING function to check if anything is listening on given port.
<?php
* This script uses CURL to check if given HOST is serving a webpage.
* If NOT, use a PING function to check if anything is listening on given port.
//* URL MUST contain a PORT after HOST
//* URL CAN include any protocol or sub-path
// sanitizes URL to host:port:path ONLY. (if PORT, PATH don't exist, it is ignored):
function url_to_domain($url) {
$url = 'http://google.com:80';
echo "Input URL ..... $url<br />\n";
$host = parse_url($url, PHP_URL_HOST);
$port = parse_url($url, PHP_URL_PORT);
$path = parse_url($url, PHP_URL_PATH);
// If the URL can't be parsed, use the original URL
// Change to "return false" if you don't want that
if (!$host)
echo "fail";
// $host = $url;
// remove "http/s" and "www" :
if (substr($host, 0, 4) == "www.")
$host = substr($host, 4);
if (strlen($host) > 50)
$host = substr($host, 0, 47) . '...';
// contruct sanitized URL, add ":port/path" to HOST:
return $host . ":" . $port . $path;
}
// pings "sanitized" URL:
$url = (url_to_domain($url));
$fp = pfsockopen($url, $errno, $errstr, $timeout = 5);
if (!$fp) {
echo "Ping URL ...... $url <br />\n ";
echo "URL status ..... CLOSED <br />\n";
echo "Error ............... $errstr ($errno)<br />\n";
}
else {
// $out = "GET / HTTP/1.1\r\n";
// $out .= "$url\r\n";
// $out .= "Connection: Close\r\n\r\n";
//fwrite ($fp, $out);
//displays header:
/*
while (!feof($fp)) {
echo fgets($fp, 128);
}
*/
// fclose($fp);
echo "Ping URL ...... $url <br />\n ";
echo "URL status .... OPEN";
}
?>
Related
I have a small script which gets basic information like the server IP-, and the MAC-address of the server the script is running on, I am then posting the results to a mysql database, this works fine and the code is shown below. However when I use a cronjob to execute the script everything but the IP address is being stored, for some reason the $_SERVER['SERVER_ADDR'] is blank when being executed as a cronjob.
This script runs every min, and is run on multi Raspberry PI's so I can tell which is connected to share job requests.
$mac_address = getMacLinux();
$server_ip = $config['server_ip'];
$client_ip = $_SERVER['SERVER_ADDR'];
$client_name = $config['client_name'];
$ch = curl_init();
$url = "{$server_ip}/checkin0.php";
echo "url = {$url}"."<br>";
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, "client_ip={$client_ip}&client_name={$client_name}&client_mac={$mac_address}");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$output = curl_exec ($ch); // Execute
curl_close ($ch); // Close cURL handle
var_dump($output); // Show output
i found the following
function getServerAddress() {
if(isset($_SERVER["SERVER_ADDR"]))
return $_SERVER["SERVER_ADDR"];
else {
// Running CLI
if(stristr(PHP_OS, 'WIN')) {
// Rather hacky way to handle windows servers
exec('ipconfig /all', $catch);
foreach($catch as $line) {
if(eregi('IP Address', $line)) {
// Have seen exec return "multi-line" content, so another hack.
if(count($lineCount = split(':', $line)) == 1) {
list($t, $ip) = split(':', $line);
$ip = trim($ip);
} else {
$parts = explode('IP Address', $line);
$parts = explode('Subnet Mask', $parts[1]);
$parts = explode(': ', $parts[0]);
$ip = trim($parts[1]);
}
if(ip2long($ip > 0)) {
echo 'IP is '.$ip."\n";
return $ip;
} else
; // TODO: Handle this failure condition.
}
}
} else {
$ifconfig = shell_exec('/sbin/ifconfig eth0');
preg_match('/addr:([\d\.]+)/', $ifconfig, $match);
return $match[1];
}
Look in the manual
$_SERVER is an array containing information such as headers, paths, and script locations. The entries in this array are created by the web server
PS. Also you can use your script as CGI script (and $_SERVER['SERVER_ADDRESS'] will be correct). You may try fetch, wget, curl... and call script from crontab i.e. (server-IP is 192.168.0.1):
1 * * * * fetch http://192.168.0.1/my_script.php
I want to see if a website can be accessed or not with a PHP page.
Here is my plan:
<?php
$website = /* bool to see if site is up */
if($website)
{
echo'<iframe src="http://64.126.89.241/" width="100%" height="100%"/>';
}else
{
echo'<iframe src="http://tsiserver.us/backup/" width="100%" height="100%"/>';
}
?>
The website will be hosted on another server, therefore if my internet goes down, a user may access the backup version of a site.
Here is a simple function that will determine if a website exists using PHP and cURL
function urlExists($url=NULL)
{
if($url == NULL) return false;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if($httpcode>=200 && $httpcode<300){
return true;
} else {
return false;
}
}
This was grabbed from this post on how to check if a URL exists. Because Twitter should provide an error message above 300 when it is in maintenance, or a 404, this should work perfectly.
reference : https://stackoverflow.com/a/1239090/568414
Based on your approach, you would need 3 different servers:
The server that hosts the script
The server that hosts the website
The server that hosts the fallback website
This is not so efficient and many hosting services provide fallback or cached versions of your site in case it's down, automatically. You don't have to mess with a script for this, but if you insist, you can refer to PHP's curl manual.
The answer is here, thanks guys!
<?php
function ping($host, $port, $timeout) {
$tB = microtime(true);
$fP = fSockOpen($host, $port, $errno, $errstr, $timeout);
if (!$fP) { return "down"; }
$tA = microtime(true);
return round((($tA - $tB) * 1000), 0)." ms";
}
$website = ping("64.126.89.241", 80, 10);
if($website != "down"){
echo'<iframe src="http://64.126.89.241/" width="100%" height="100%"/>';
}else{
echo'<iframe src="http://tsiserver.us/backup/" width="100%" height="100%"/>';
}
?>
In javascript or jquery you a function can do a callback to remote webpage. The remote page does some processing and something/nothing maybe returned to the calling function.
For example: $.ajax(http://someurl.php?querystring)
How do I do this in php?
<?php
'Doing some stuff
remote_call(http://someurl.php?querystring) 'Let the page know I did stuff
'more php
?>
Everywhere I can find is either talking about a php function callback or reading file contents. I don't want to read the file contents, I just want to call the remote page and move on. Is it possible?
I can't answer my own question in this forum so I am putting the answer here.
Here is what worked for me. YMMV
$host = "http://somedomain.com/process.php?querystring";
curlMe($host);
function curlMe($host)
{
$ch = curl_init($host);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
}
You could just make a async request to the remote page by closing the socket immediately so the php code doesn't block and forget about the result.
<?php
private function request($body) {
$protocol = "http";
$host = "domain.com";
$port = 80;
$path = "/somepage.php" . $body;
$timeout = 10;
try {
# Open our socket to the API Server.
$socket = fsockopen($protocol . "://" . $host, $port,
$errno, $errstr, $timeout);
# Create the request body, and make the request.
$req = $this->create_body($host, $path, $content);
fwrite($socket, $req);
# ...
} catch (Exception $e) {
# ...
}
}
?>
I'm currently trying to get PHP to login and authenticate with a CAS single sign on server which is proving difficult.
The official site has some basic source code here which is supposed to handle the authentication and log in a user. As far as I can see and in my testing it completes steps 1 and 2 in the process (see this diagram for the basic process). Once I've logged into the test server I can complete step 3 and retrieve the service ticket from the URL that sent me back to my page. There doesn't seem to be any examples anywhere to complete steps 4 and 5 of the process. Is it correct that I need to write my own code to do that?
I have attempted to get the ticket back and then send it off to the validation service using some of my own code with cURL or fsockopen with no luck.
if (isset($_GET['ticket']))
{
$currentProtocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') ? 'https://' : 'http://';
$requestUri = explode('?', $_SERVER['REQUEST_URI']);
$requestUri = $requestUri[0];
$ticket = $_GET['ticket'];
$port = ($_SERVER['SERVER_PORT'] != 80) ? ':8080' : '';
$currentUrl = urlencode($currentProtocol . $_SERVER['SERVER_NAME'] . $port . $requestUri);
$validateUrl = 'ssl://server.com/cas/serviceValidate?service=' . $currentUrl . '&ticket=' . $ticket;
$errno = 0;
$errstr = '';
$fp = fsockopen($validateUrl, 443, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
}
else {
var_dump($fp);
$out = "GET / HTTP/1.1\r\n";
$out .= "Host: www.example.com\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!feof($fp)) {
echo fgets($fp, 128);
}
fclose($fp);
}
}
I can get a legitimate response from the service if I access it through the browser directly e.g:
https://server.com/cas/serviceValidate?service=http%3A%2F%2Flocalhost%3A8080%2Ftestcas%2Fcas-client.php&ticket=ST-35717-XLiWQ2ucCCuks2wsVNMJ-cas
Which returns an XML response containing the Active Directory User ID:
<cas:serviceResponse xmlns:cas='http://www.server.com/cas'>
<cas:authenticationSuccess>
<cas:user>c314317</cas:user>
</cas:authenticationSuccess>
</cas:serviceResponse>
But I really think I need to be able to access that URL directly from the server side with PHP, then once I have the user ID I can link that back with our systems and log them into the site.
My problem is there doesn't seem to be any code to handle the ticket and validation side of things. Can anyone point me in the right direction?
Thanks very much.
OK I think I solved the problem with cURL. I didn't have the CURLOPT_SSL_VERIFYPEER set to false and that's why it was failing. I can now get the XML response with PHP, process the XML response and retrieve the user ID. Here's the code:
// Get the current server address we are executing the PHP from
$currentProtocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') ? 'https://' : 'http://';
$requestUri = explode('?', $_SERVER['REQUEST_URI']);
$requestUri = $requestUri[0];
$ticket = $_GET['ticket'];
$port = ($_SERVER['SERVER_PORT'] != 80) ? ':' . $_SERVER['SERVER_PORT'] : ''; # Don't need the port if it's 80, but needed if for example test server is running port 8080
$currentUrl = $currentProtocol . $_SERVER['SERVER_NAME'] . $port . $requestUri;
// Setup the validation URL
$validateUrl = 'https://sso.server.com/cas/serviceValidate?service=' . strtolower(urlencode($currentUrl)) . '&ticket=' . $ticket;
// Send request to validate the URL
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $validateUrl); # The URL to get the data from
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); # Return the value of curl_exec() instead of outputting it out directly.
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 120); # The number of seconds to wait while trying to connect
curl_setopt($ch, CURLOPT_TIMEOUT, 120); # The maximum number of seconds to allow cURL functions to execute
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); # Check the existence of a common name and also verify that it matches the hostname provided
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); # Stop cURL from verifying the peer's certificate
curl_setopt($ch, CURLOPT_HEADER, false); # Don't include the header in the output
// Execute the request and close the handle
$xml = curl_exec($ch);
curl_close($ch);
// Get the user ID from the XML using XPath
$xml = new SimpleXMLElement($xml);
$result = $xml->xpath('cas:authenticationSuccess/cas:user');
$userId = null;
while(list( , $node) = each($result))
{
$userId = (string) $node;
}
echo 'user: ' . $userId . "<br>";
I need to create a function that returns if a URL is reachable or valid.
I am currently using something like the following to determine a valid url:
static public function urlExists($url)
{
$fp = #fopen($url, 'r');
if($fp)
{
return true;
}
return false;
}
It seems like there would be something faster, maybe something that just fetched the page header or something.
You can use curl as follows:
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_NOBODY, true); // set to HEAD request
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // don't output the response
curl_exec($ch);
$valid = curl_getinfo($ch, CURLINFO_HTTP_CODE) == 200;
curl_close($ch);
You could check http status code.
Here is a code you could use to check that an url returns 2xx or 3xx http code to ensure the url works.
<?php
$url = "http://stackoverflow.com/questions/1122845";
function urlOK($url)
{
$url_data = parse_url ($url);
if (!$url_data) return FALSE;
$errno="";
$errstr="";
$fp=0;
$fp=fsockopen($url_data['host'],80,$errno,$errstr,30);
if($fp===0) return FALSE;
$path ='';
if (isset( $url_data['path'])) $path .= $url_data['path'];
if (isset( $url_data['query'])) $path .= '?' .$url_data['query'];
$out="GET /$path HTTP/1.1\r\n";
$out.="Host: {$url_data['host']}\r\n";
$out.="Connection: Close\r\n\r\n";
fwrite($fp,$out);
$content=fgets($fp);
$code=trim(substr($content,9,4)); //get http code
fclose($fp);
// if http code is 2xx or 3xx url should work
return ($code[0] == 2 || $code[0] == 3) ? TRUE : FALSE;
}
echo $url;
if (urlOK($url)) echo " is a working URL";
else echo " is a bad URL";
?>
Hope this helps!
You'll likely be limited to sending some kind of HTTP request. Then you can check HTTP status codes.
Be sure to send only a "HEAD" request, which doesn't pull back all the content. That ought to be sufficient and lightweight enough.