Difficulties using PHP to authenticate with CAS - php

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>";

Related

How to login to girisv3.itu.edu.tr with php/curl?

I am trying to login this website över mu website (i.e localhost)
https://girisv3.itu.edu.tr/Login.aspx
According to example code shared at here for facebook login on other website (localhost)
PHP cURL to login to facebook
I am trying to apply this Facebook login for itu.edu.tr login. But it didnt work. I am also newbie to curl and php. How can I do that for this website (itu.edu.tr)?
<?php
$username = 'username#itu.edu.tr';
$password = 'password';
$loginUrl = 'https://girisv3.itu.edu.tr/Login.aspx';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $loginUrl);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'ContentPlaceHolder1_tbUserName='.$username.'&ContentPlaceHolder1_tbPassword='.$password.'&ContentPlaceHolder1_btnLogin=Login');
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_COOKIEJAR, "cookies.txt");
curl_setopt($ch, CURLOPT_COOKIEFILE, "cookies.txt");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_REFERER, "http://www.itu.edu.tr");
//execute the request
$content = curl_exec($ch);
echo $content;
?>
the login system at girisv3.itu.edu.tr has little in common with the facebook login system (i can say that with confidence because i've studied facebook's login system and written code that logs into facebook )
to login here, first hit https://girisv3.itu.edu.tr/Login.aspx with a simple HTTP GET request, here you'll be redirected 5 times (why? no friggin idea, albeit at least 2 of them are to test that you have cookies enabled) with HTTP Location-redirects , on the first redirect you will get a cookie looking like Set-Cookie: ASP.NET_SessionId=fzwd05uqv2ogyvj2p4ip2x3u; path=/; HttpOnly, save that and re-use it on all following redirects (if you do not, you will get an error like The ITU Introduction application uses cookies. Your browser has been found to block cookies. Please allow cookies from the browser settings and try again later.), and on the last request you will get a cookie looking like Cookie: ASP.NET_SessionId=nmhigw3julmzbedva0zwklj2; cookieCheck=true, this is the cookie you need to actually log in. (cookieCheck=true probably means that you passed the cookie test), once you're finished with the redirects, the HTML contains a lot of data that you need to parse out to log in, a <form element contains a unique url specific to your cookie where you need to send the POST request to log in, it looks like
<form method="post" action="./Login.aspx?subSessionId=543cf6e7-d262-46f3-8207-740d92298bd3&currentURL=https%3a%2f%2fportal.itu.edu.tr%2flogin.aspx%3fReturnUrl%3d%252fapps%252fdefault%252f&cookieAdded=true" id="form1">
and there are a bunch of <input> elements containing data that you also need to parse out and add to the actual login request, specifically
__VIEWSTATE and __VIEWSTATEGENERATOR and __EVENTVALIDATION and ctl00$ContentPlaceHolder1$hfAppName and ctl00$ContentPlaceHolder1$hfToken and ctl00$ContentPlaceHolder1$hfVerifier and ctl00$ContentPlaceHolder1$hfCode and ctl00$ContentPlaceHolder1$hfState and (this 1 is the login username by the way) ctl00$ContentPlaceHolder1$tbUserName
and (this 1 is the login password) ctl00$ContentPlaceHolder1$tbPassword and ctl00$ContentPlaceHolder1$btnLogin
once you have the login POST data parsed out from the html, add the login username to ctl00$ContentPlaceHolder1$tbUserName and add the login password to ctl00$ContentPlaceHolder1$tbPassword, and send the actual login request to the url obtained from the <form element together with the cookie received in the last http-redirect, the data must be encoded in the application/x-www-form-urlencoded-format (and PHP has a native function for encoding php arrays in application/x-www-form-urlencoded-format called http_build_query)
here is an example with hhb_curl (a php curl_ api wrapper which takes care of error detection (turning silent curl errors into RuntimeExceptions), cookies, following Location redirects, freeing curl resources, and then some)
<?php
declare (strict_types = 1);
const USERNAME = "TheUsername";
const PASSWORD = "ThePassword";
require_once('hhb_.inc.php');
$hc = new hhb_curl('', true);
$html = $hc->exec('https://girisv3.itu.edu.tr/Login.aspx')->getStdOut();
$domd = #DOMDocument::loadHTML($html);
$xp = new DOMXPath($domd);
$loginForm = $domd->getElementById("form1");
$login_url = 'https://girisv3.itu.edu.tr/' . $loginForm->getAttribute("action");
$postDataInputNames = array(
'__VIEWSTATE',
'__VIEWSTATEGENERATOR',
'__EVENTVALIDATION',
'ctl00$ContentPlaceHolder1$hfAppName',
'ctl00$ContentPlaceHolder1$hfToken',
'ctl00$ContentPlaceHolder1$hfVerifier',
'ctl00$ContentPlaceHolder1$hfCode',
'ctl00$ContentPlaceHolder1$hfState',
'ctl00$ContentPlaceHolder1$tbUserName',
'ctl00$ContentPlaceHolder1$tbPassword',
'ctl00$ContentPlaceHolder1$btnLogin',
);
$postData = [];
foreach ($postDataInputNames as $name) {
$ele = $xp->query('.//input[#name=' . xpath_quote($name) . ']', $loginForm);
if (!$ele->length) {
var_dump($html);
throw new \LogicException("failed to find input form {$name}!");
}
$ele = $ele->item(0);
$postData[$name] = $ele->getAttribute("value");
}
$postData['ctl00$ContentPlaceHolder1$tbUserName'] = USERNAME;
$postData['ctl00$ContentPlaceHolder1$tbPassword'] = PASSWORD;
var_dump('login post data: ', $postData);
$html = $hc->setopt_array(array(
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => http_build_query($postData),
CURLOPT_URL => $login_url,
))->exec()->getStdOut();
$domd = #DOMDocument::loadHTML('<?xml encoding="UTF-8">' . $html);
$xp = new DOMXPath($domd);
$loginError = $domd->getElementById("ContentPlaceHolder1_lbHata");
if ($loginError && !empty(trim($loginError->textContent))) {
echo "LOGIN ERROR: " . trim($loginError->textContent) . "\n";
} else {
echo "Login success! ";
var_dump($html);
}
//based on https://stackoverflow.com/a/1352556/1067003
function xpath_quote(string $value) : string
{
if (false === strpos($value, '"')) {
return '"' . $value . '"';
}
if (false === strpos($value, '\'')) {
return '\'' . $value . '\'';
}
// if the value contains both single and double quotes, construct an
// expression that concatenates all non-double-quote substrings with
// the quotes, e.g.:
//
// concat("'foo'", '"', "bar")
$sb = 'concat(';
$substrings = explode('"', $value);
for ($i = 0; $i < count($substrings); ++$i) {
$needComma = ($i > 0);
if ($substrings[$i] !== '') {
if ($i > 0) {
$sb .= ', ';
}
$sb .= '"' . $substrings[$i] . '"';
$needComma = true;
}
if ($i < (count($substrings) - 1)) {
if ($needComma) {
$sb .= ', ';
}
$sb .= "'\"'";
}
}
$sb .= ')';
return $sb;
}
which yields:
LOGIN ERROR: Kullanıcı adı veya şifre hatalı.
which means the username/password is invalid, because apparently TheUsername and ThePassword is not valid login credentials.
all the information required to login can be obtained by installing Fiddler Proxy, and record logging in with a browser (like FireFox), and then replicate the browser login procedure with php/curl, which is basically what i did here.

How to use "fallback" method for PHP curl (HTTPS)?

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";
}
?>

PHP cPanel Create Subdomain

So I am trying to automatically create subdomains for my website using PHP. I tried the following code but it gives me a 301 error and redirects me to my cPanel login
function createDomain($domain) {
// your cPanel username
$cpanel_user = 'User';
// your cPanel password
$cpanel_pass = 'Pass';
// your cPanel skin
$cpanel_skin = 'paper_lantern';
// your cPanel domain
$cpanel_host = 'example.com';
// subdomain name
$subdomain = $domain;
// directory - defaults to public_html/subdomain_name
$dir = 'public_html/user_site';
// create the subdomain
$sock = fsockopen($cpanel_host,2083);
if(!$sock) {
print('Socket error');
exit();
}
$pass = base64_encode("$cpanel_user:$cpanel_pass");
$in = "GET /frontend/$cpanel_skin/subdomain/doadddomain.html?rootdomain=$cpanel_host&domain=$subdomain&dir=$dir\r\n";
$in .= "HTTP/1.0\r\n";
$in .= "Host:$cpanel_host\r\n";
$in .= "Authorization: Basic $pass\r\n";
$in .= "\r\n";
fputs($sock, $in);
while (!feof($sock)) {
$result .= fgets ($sock,128);
}
fclose($sock);
return $result;
}
Like I said it gives me a 301 error and redirects to example.com:2083 instead of just doing it in the code and not having me login to the cPanel manually. Any help would be greatly appreciated!
ANSWER:
After fiddling with my code I realized that port 2082 and port 2083 are the same except that 2082 has no https:// so I changed the port to 2082 and it worked!
CODE:
function createDomain($domain) {
// your cPanel username
$cpanel_user = 'User';
// your cPanel password
$cpanel_pass = 'Pass';
// your cPanel skin
$cpanel_skin = 'paper_lantern';
// your cPanel domain
$cpanel_host = 'example.com';
// subdomain name
$subdomain = $domain;
// directory - defaults to public_html/subdomain_name
$dir = 'public_html/user_site';
// create the subdomain
$sock = fsockopen($cpanel_host,2082);
if(!$sock) {
print('Socket error');
exit();
}
$pass = base64_encode("$cpanel_user:$cpanel_pass");
$in = "GET /frontend/$cpanel_skin/subdomain/doadddomain.html?rootdomain=$cpanel_host&domain=$subdomain&dir=$dir\r\n";
$in .= "HTTP/1.0\r\n";
$in .= "Host:$cpanel_host\r\n";
$in .= "Authorization: Basic $pass\r\n";
$in .= "\r\n";
fputs($sock, $in);
while (!feof($sock)) {
$result .= fgets ($sock,128);
}
fclose($sock);
return $result;
}
API 1 is now dead. Also passing your cpanel password through a non-secure connection (ie port 2082 instead of 2083) is a very bad idea. Next thing you know someone will have hijacked your cpanel account!
However, combining the codes given here for authentication and here for adding a subdomain, gives us the following script which seems to work just fine:
<?php
$cpanelsername = "example";
$cpanelpassword = "**********";
$subdomain = 'newsubdomain';
$domain = 'example.com';
$directory = "/public_html/$subdomain"; // A valid directory path, relative to the user's home directory. Or you can use "/$subdomain" depending on how you want to structure your directory tree for all the subdomains.
$query = "https://$domain:2083/json-api/cpanel?cpanel_jsonapi_func=addsubdomain&cpanel_jsonapi_module=SubDomain&cpanel_jsonapi_version=2&domain=$subdomain&rootdomain=$domain&dir=$directory";
$curl = curl_init(); // Create Curl Object
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER,0); // Allow self-signed certs
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST,0); // Allow certs that do not match the hostname
curl_setopt($curl, CURLOPT_HEADER,0); // Do not include header in output
curl_setopt($curl, CURLOPT_RETURNTRANSFER,1); // Return contents of transfer on curl_exec
$header[0] = "Authorization: Basic " . base64_encode($whmusername.":".$whmpassword) . "\n\r";
curl_setopt($curl, CURLOPT_HTTPHEADER, $header); // set the username and password
curl_setopt($curl, CURLOPT_URL, $deletedir); // execute the query
$result = curl_exec($curl);
if ($result == false) {
error_log("curl_exec threw error \"" . curl_error($curl) . "\" for $query");
// log error if curl exec fails
}
curl_close($curl);
print $result;
?>
The result should be something like this:
{"cpanelresult":{"func":"addsubdomain","event":{"result":1},"apiversion":2,"module":"SubDomain","data":[{"reason":"The subdomain “newsubdomain.example.com” has been added.","result":1}],"preevent":{"result":1},"postevent":{"result":1}}}
To delete the subdomain, run this query through the above script:
$deletesub = "https://$domain:2083/json-api/cpanel?cpanel_jsonapi_func=delsubdomain&cpanel_jsonapi_module=SubDomain&cpanel_jsonapi_version=2&domain=".$subdomain.'.'.$domain."&dir=$directory"; //Note: To delete the subdomain of an addon domain, separate the subdomain with an underscore (_) instead of a dot (.). For example, use the following format: subdomain_addondomain.tld
And to delete the directory, run this:
$deletedir = "https://$domain:2083/json-api/cpanel?cpanel_jsonapi_module=Fileman&cpanel_jsonapi_func=fileop&op=unlink&sourcefiles=$directory";
Noel's answer from 2018 more than likely won't work anymore, but if you've come here looking for how to use the Cpanel API to add a subdomain, start at this link to see the arguments accepted for the Cpanel API Ver 2 for the SubDomain module addsubdomain.
Below is an example that worked perfectly well for me.
$whmusername = "cpanel_username";
$whmpassword = "cpanel_password";
$subdomain = 'newsubdomain';
$cpanel_ip = 'IP_ADDRESS'; //ip of cpanel or your_domain.com
$domain = "your_domain.com";
$query = "https://".$cpanel_ip."2083/json-api/cpanel?cpanel_jsonapi_module=SubDomain&cpanel_jsonapi_func=addsubdomain&cpanel_jsonapi_apiversion=2&dir=/public_html/".$subdomain.".".$domain."/&rootdomain=".$domain."&domain=".$subdomain."";
$curl = curl_init();
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER,0);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST,0);
curl_setopt($curl, CURLOPT_HEADER,0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER,1);
$header[0] = "Authorization: Basic " . base64_encode($whmusername.":".$whmpassword) . "\n\r";
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl, CURLOPT_URL, $query);
$result = curl_exec($curl);
curl_close($curl);
Note that if you want to see what Cpanel is returning as a response for $result, then place print $result; after curl_close($curl);

Get the real video URL from a url

I'm trying to get the real file URL from a url that doesn't show up the real file name.
My url is like this http://video.premium.com/file/ee7bfec921cfbe16e6f08e282992b99670a00ca3/3
If I could get the real file url I could stream it directly online through a web player, but it needs .mp4 or other file format to play, just the url http://video.premium.com/file/ee7bfec921cfbe16e6f08e282992b99670a00ca3/3 doesnt work.
but when I open the URL using VLC media player, it works. doesn't work with online flash or other players..
Is this even possible? Anyway to do this?
With curl, use this: It follows the redirect until it finds the endpoint. In the included code I used goo.gl to shorten the url to a rando image. You will see the output is the original link (and it would output whatever number of redirects and their URLs), and the final redirect to the actual file. I think this is what you are looking for. I did not write this originally, but found it somewhere some time ago and reused it many times again with tweaking when needed. It seems to fit well in many places. Glad to pass it on. I think it might help to achieve what you are looking for.
<?php
function follow_redirect($url){
$redirect_url = null;
if(function_exists("curl_init")){
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
}
else{
$url_parts = parse_url($url);
$sock = fsockopen($url_parts['host'], (isset($url_parts['port']) ? (int)$url_parts['port'] : 80));
$request = "HEAD " . $url_parts['path'] . (isset($url_parts['query']) ? '?'.$url_parts['query'] : '') . " HTTP/1.1\r\n";
$request .= 'Host: ' . $url_parts['host'] . "\r\n";
$request .= "Connection: Close\r\n\r\n";
fwrite($sock, $request);
$response = fread($sock, 2048);
fclose($sock);
}
$header = "Location: ";
$pos = strpos($response, $header);
if($pos === false){
return false;
}
else{
$pos += strlen($header);
$redirect_url = substr($response, $pos, strpos($response, "\r\n", $pos)-$pos);
return $redirect_url;
}
}
$url = 'http://goo.gl/66VJB';
echo '<ol>';
while(($newurl = follow_redirect($url)) !== false){
echo '<li>', $url, '</li>';
$url = $newurl;
}
echo '</ol>';
echo '', $url, '';
?>
Output:
http://goo.gl/66VJB
http://1.bp.blogspot.com/_XE0TDW07Noo/TOSVQXZtgAI/AAAAAAAAELo/aG80jZ7u_fo/s1600/aptitude_test.gif

PHP: Check if URL redirects?

I have implemented a function that runs on each page that I want to restrict from non-logged in users. The function automatically redirects the visitor to the login page in the case of he or she is not logged in.
I would like to make a PHP function that is run from a exernal server and iterates through a number of set URLs (array with URLs that is for each protected site) to see if they are redirected or not. Thereby I could easily make sure if protection is up and running on every page.
How could this be done?
Thanks.
$urls = array(
'http://www.apple.com/imac',
'http://www.google.com/'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
foreach($urls as $url) {
curl_setopt($ch, CURLOPT_URL, $url);
$out = curl_exec($ch);
// line endings is the wonkiest piece of this whole thing
$out = str_replace("\r", "", $out);
// only look at the headers
$headers_end = strpos($out, "\n\n");
if( $headers_end !== false ) {
$out = substr($out, 0, $headers_end);
}
$headers = explode("\n", $out);
foreach($headers as $header) {
if( substr($header, 0, 10) == "Location: " ) {
$target = substr($header, 10);
echo "[$url] redirects to [$target]<br>";
continue 2;
}
}
echo "[$url] does not redirect<br>";
}
I use curl and only take headers, after I compare my url and url from header curl:
$url="http://google.com";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_TIMEOUT, '60'); // in seconds
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_NOBODY, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$res = curl_exec($ch);
if(curl_getinfo($ch)['url'] == $url){
echo "not redirect";
}else {
echo "redirect";
}
You could always try adding:
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
since 302 means it moved, allow the curl call to follow it and return whatever the moved url returns.
Getting the headers with get_headers() and checking if Location is set is much simpler.
$urls = [
"https://example-1.com",
"https://example-2.com"
];
foreach ($urls as $key => $url) {
$is_redirect = does_url_redirect($url) ? 'yes' : 'no';
echo $url . ' is redirected: ' . $is_redirect . PHP_EOL;
}
function does_url_redirect($url){
$headers = get_headers($url, 1);
if (!empty($headers['Location'])) {
return true;
} else {
return false;
}
}
I'm not sure whether this really makes sense as a security check.
If you are worried about files getting called directly without your "is the user logged in?" checks being run, you could do what many big PHP projects do: In the central include file (where the security check is being done) define a constant BOOTSTRAP_LOADED or whatever, and in every file, check for whether that constant is set.
Testing is great and security testing is even better, but I'm not sure what kind of flaw you are looking to uncover with this? To me, this idea feels like a waste of time that will not bring any real additional security.
Just make sure your script die() s after the header("Location:...") redirect. That is essential to stop additional content from being displayed after the header command (a missing die() wouldn't be caught by your idea by the way, as the redirect header would still be issued...)
If you really want to do this, you could also use a tool like wget and feed it a list of URLs. Have it fetch the results into a directory, and check (e.g. by looking at the file sizes that should be identical) whether every page contains the login dialog. Just to add another option...
Do you want to check the HTTP code to see if it's a redirect?
$params = array('http' => array(
'method' => 'HEAD',
'ignore_errors' => true
));
$context = stream_context_create($params);
foreach(array('http://google.com', 'http://stackoverflow.com') as $url) {
$fp = fopen($url, 'rb', false, $context);
$result = stream_get_contents($fp);
if ($result === false) {
throw new Exception("Could not read data from {$url}");
} else if (! strstr($http_response_header[0], '301')) {
// Do something here
}
}
I hope it will help you:
function checkRedirect($url)
{
$headers = get_headers($url);
if ($headers) {
if (isset($headers[0])) {
if ($headers[0] == 'HTTP/1.1 302 Found') {
//this is the URL where it's redirecting
return str_replace("Location: ", "", $headers[9]);
}
}
}
return false;
}
$isRedirect = checkRedirect($url);
if(!$isRedirect )
{
echo "URL Not Redirected";
}else{
echo "URL Redirected to: ".$isRedirect;
}
You can use session,if the session array is not set ,the url redirected to a login page.
.
I modified Adam Backstrom answer and implemented chiborg suggestion. (Download only HEAD). It have one thing more: It will check if redirection is in a page of the same server or is out. Example: terra.com.br redirects to terra.com.br/portal. PHP will considerate it like redirect, and it is correct. But i only wanted to list that url that redirect to another URL. My English is not good, so, if someone found something really difficult to understand and can edit this, you're welcome.
function RedirectURL() {
$urls = array('http://www.terra.com.br/','http://www.areiaebrita.com.br/');
foreach ($urls as $url) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// chiborg suggestion
curl_setopt($ch, CURLOPT_NOBODY, true);
// ================================
// READ URL
// ================================
curl_setopt($ch, CURLOPT_URL, $url);
$out = curl_exec($ch);
// line endings is the wonkiest piece of this whole thing
$out = str_replace("\r", "", $out);
echo $out;
$headers = explode("\n", $out);
foreach($headers as $header) {
if(substr(strtolower($header), 0, 9) == "location:") {
// read URL to check if redirect to somepage on the server or another one.
// terra.com.br redirect to terra.com.br/portal. it is valid.
// but areiaebrita.com.br redirect to bwnet.com.br, and this is invalid.
// what we want is to check if the address continues being terra.com.br or changes. if changes, prints on page.
// if contains http, we will check if changes url or not.
// some servers, to redirect to a folder available on it, redirect only citting the folder. Example: net11.com.br redirect only to /heiden
// only execute if have http on location
if ( strpos(strtolower($header), "http") !== false) {
$address = explode("/", $header);
print_r($address);
// $address['0'] = http
// $address['1'] =
// $address['2'] = www.terra.com.br
// $address['3'] = portal
echo "url (address from array) = " . $url . "<br>";
echo "address[2] = " . $address['2'] . "<br><br>";
// url: terra.com.br
// address['2'] = www.terra.com.br
// check if string terra.com.br is still available in www.terra.com.br. It indicates that server did not redirect to some page away from here.
if(strpos(strtolower($address['2']), strtolower($url)) !== false) {
echo "URL NOT REDIRECT";
} else {
// not the same. (areiaebrita)
echo "SORRY, URL REDIRECT WAS FOUND: " . $url;
}
}
}
}
}
}
function unshorten_url($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $url);
$out = curl_exec($ch);
$real_url = $url;//default.. (if no redirect)
if (preg_match("/location: (.*)/i", $out, $redirect))
$real_url = $redirect[1];
if (strstr($real_url, "bit.ly"))//the redirect is another shortened url
$real_url = unshorten_url($real_url);
return $real_url;
}
I have just made a function that checks if a URL exists or not
$ch = curl_init();
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
function url_exists($url, $ch) {
curl_setopt($ch, CURLOPT_URL, $url);
$out = curl_exec($ch);
// line endings is the wonkiest piece of this whole thing
$out = str_replace("\r", "", $out);
// only look at the headers
$headers_end = strpos($out, "\n\n");
if( $headers_end !== false ) {
$out = substr($out, 0, $headers_end);
}
//echo $out."====<br>";
$headers = explode("\n", $out);
//echo "<pre>";
//print_r($headers);
foreach($headers as $header) {
//echo $header."---<br>";
if( strpos($header, 'HTTP/1.1 200 OK') !== false ) {
return true;
break;
}
}
}
Now I have used an array of URLs to check if a URL exists as following:
$my_url_array = array('http://howtocode.pk/result', 'http://google.com/jobssss', 'https://howtocode.pk/javascript-tutorial/', 'https://www.google.com/');
for($j = 0; $j < count($my_url_array); $j++){
if(url_exists($my_url_array[$j], $ch)){
echo 'This URL "'.$my_url_array[$j].'" exists. <br>';
}
}
I can't understand your question.
You have an array with URLs and you want to know if user is from one of the listed URLs?
If I'm right in understanding your quest:
$urls = array('http://url1.com','http://url2.ru','http://url3.org');
if(in_array($_SERVER['HTTP_REFERER'],$urls))
{
echo 'FROM ARRAY';
} else {
echo 'NOT FROM ARR';
}

Categories