PHP - Cant connect to RETS via PHRETS - php

I am trying to get all my MLS listing via PHP using PHRETS which I downloaded from here:
https://github.com/dangodev/PHRETS-Example/blob/master/lib/phrets.php
and I used this example to download my listings into a csv format:
https://github.com/troydavisson/PHRETS/wiki/Connect,%20download%20listing%20data%20in%20CSV%20format,%20disconnect
I got the RETS URL, username and password from my MLS board, but I still can’t connect.
My code returns false when call the PHRETS library here:
require_once("phrets.php");
// start rets connection
$rets = new phRETS;
echo "+ Connecting to {$rets_login_url} as {$rets_username}<br>\n";
$connect = $rets->Connect($rets_login_url, $rets_username, $rets_password);
if ($connect) {
echo " + Connected<br>\n";
}
else {
echo " + Not connected:<br>\n";
print_r($rets->Error());
exit;
}
When I goto to library and look at the method Connect, that code returns false here:
// make request to Login transaction
$result = $this->RETSRequest($this->capability_url['Login']);
if (!$result) {
return false;
}
And when I look at my RETSRequest Method, it returns false here because the response code is 0 and not 200
if ($response_code != 200) {
$this->set_error_info("http", $response_code, $response_body);
return false;
}
and here is where its trying to connect:
if ($this->ua_auth == true) {
$session_id_to_calculate_with = "";
// calculate RETS-UA-Authorization header
$ua_a1 = md5($this->static_headers['User-Agent'] .':'. $this->ua_pwd);
$session_id_to_calculate_with = ($this->use_interealty_ua_auth == true) ? "" : $this->session_id;
$ua_dig_resp = md5(trim($ua_a1) .':'. trim($this->request_id) .':'. trim($session_id_to_calculate_with) .':'. trim($this->static_headers['RETS-Version']));
$request_headers .= "RETS-UA-Authorization: Digest {$ua_dig_resp}\r\n";
}
$this->last_request_url = $request_url;
curl_setopt($this->ch, CURLOPT_URL, $request_url);
curl_setopt($this->ch, CURLOPT_HTTPHEADER, array(trim($request_headers)));
// do it
$response_body = curl_exec($this->ch);
$response_code = curl_getinfo($this->ch, CURLINFO_HTTP_CODE);
Why can’t I connect?
I was able to login via http://retsmd.com with the url, username and password. I really need to get my listings in the format of CSV.
PLEASE HELP
I do have curl installed on my server, I checked with this method:
Check to see if cURL is installed locally?

A response code of 0 usually indicates that your server failed to open a connection with the server, likely due to firewall issues between you and them. Some RETS servers still run on a port 6103, so if your server (hosting company, etc.) prevent outbound connections from being opened on that port, that could be the cause for what you're seeing.
I'd recommend trying your code example from a different server or computer that doesn't have any connection restrictions. You could also try https://retsmd.com/auth as a way to verify that the credentials you've been given will work (assuming your local environment has what it needs for PHRETS to run).

Adding to troydavisson's answer,
You can include the following extra line of code to get the log of your connection for checking the issue.
// start rets connection
$rets = new phRETS;
$rets->SetParam('debug_mode', true);//extra line of code to get log
You will get full log in the rets_debug.txt file.

Related

PHP script can't open certain URLs

I'm calling through Axios a PHP script checking whether a URL passed to it as a parameter can be embedded in an iframe. That PHP script starts with opening the URL with $_GET[].
Strangely, a page with cross-origin-opener-policy: same-origin (like https://twitter.com/) can be opened with $_GET[], whereas a page with Referrer Policy: strict-origin-when-cross-origin (like https://calia.order.liven.com.au/) cannot.
I don't understand why, and it's annoying because for the pages that cannot be opened with $_GET[] I'm unable to perform my checks on them - the script just fails (meaning I get no response and the Axios call runs the catch() block).
So basically there are 3 types of pages: (1) those who allow iframe embeddability, (2) those who don't, and (3) the annoying ones who not only don't but also can't even be opened to perform this check.
Is there a way to open any page with PHP, and if not, what can I do to prevent my script from failing after several seconds?
PHP script:
$source = $_GET['url'];
$response = true;
try {
$headers = get_headers($source, 1);
$headers = array_change_key_case($headers, CASE_LOWER);
if (isset($headers['content-security-policy'])) {
$response = false;
}
else if (isset($headers['x-frame-options']) &&
$headers['x-frame-options'] == 'DENY' ||
$headers['x-frame-options'] == 'SAMEORIGIN'
) {
$response = false;
}
} catch (Exception $ex) {
$response = $ex;
}
echo $response;
EDIT: below is the console error.
Access to XMLHttpRequest at 'https://path.to.cdn/iframeHeaderChecker?url=https://calia.order.liven.com.au/' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
CustomLink.vue?b495:61 Error: Network Error
at createError (createError.js?2d83:16)
at XMLHttpRequest.handleError (xhr.js?b50d:84)
VM4758:1 GET https://path.to.cdn/iframeHeaderChecker?url=https://calia.order.com.au/ net::ERR_FAILED
The error you have shown is coming from Javascript, not from PHP. get_headers() returns false on failure, it will not throw an exception - the catch() never happens. get_headers() just makes an http request, like your browser, or curl, and the only reason that would fail is if the URL is malformed, or the remote site is down, etc.
It is the access from http://localhost:3000 to https://path.to.cdn/iframeHeaderChecker with Javascript that has been blocked, not PHP access to the URLs you are passing as parameters in $_GET['url'].
What you're seeing is a standard CORS error when you try to access a different domain than the one the Javascript is running on. CORS means Javascript running on one host cannot make http requests to another host, unless that other host explicitly allows it. In this case, the Javascript running at http://localhost:3000 is making an http request to a remote site https://path.to.cdn/. That's a cross-origin request (localhost !== path.to.cdn), and the server/script receiving that request on path.to.cdn is not returning any specific CORS headers allowing that request, so the request is blocked.
Note though that if the request is classed as "simple", it will actually run. So your PHP is working already, always, but bcs the right headers aren't returned, the result is blocked from being displayed in your browser. This can lead to confusion bcs for eg you might notice a delay while it gets the headers from a slow site, whereas it is super fast for a fast site. Or maybe you have logging which you see is working all the time, despite nothing showing up in your browser.
My understanding is that https://path.to.cdn/iframeHeaderChecker is your PHP script, some of the code of which you have shown in your question? If so, you have 2 choices:
Update iframeHeaderChecker to return the appropriate CORS headers, so that your cross-origin JS request is allowed. As a quick, insecure hack to allow access from anyone and anywhere (not a good idea for the long term!) you could add:
header("Access-Control-Allow-Origin: *");
But it would be better to update that to more specifically restrict access to only your app, and not everyone else. You'll have to evaluate the best way to do that depending on the specifics of your application and infrastructure. There many questions here on SO about CORS/PHP/AJAX to check for reference. You could also configure this at the web server level, rather than the application level, eg here's how to configure Apache to return those headers.
If iframeHeaderChecker is part of the same application as the Javascript calling it, is it also available locally, on http://localhost:3000? If so, update your JS to use the local version, not the remote one on path.to.cdn, and you avoid the whole problem!
This is just my rough guess about what wrong with your code can be.
I noticed you do:
a comparison of values from $headers but without
ensuring they have the same CAPITAL CASE as the values you compare against. Applied: strtoupper().
check with isset() but not test if key_exist before
Applied: key_exist()
check with isset() but perhaps you should use !empty() instead of isset()
compare result:
$value = "";
var_dump(isset($value)); // (bool) true
var_dump(!empty($value)); // (bool) false
$value = "something";
var_dump(isset($value)); // (bool) true
var_dump(!empty($value)); // (bool) true
unset($value);
var_dump(isset($value)); // (bool) false
var_dump(!empty($value)); // (bool) false
The code with applied changes:
<?php
error_reporting(E_ALL);
declare(strict_types=1);
header('Access-Control-Allow-Origin: *');
ob_start();
try {
$response = true;
if (!key_exists('url', $_GET)) {
$msg = '$_GET does not have a key "url"';
throw new \RuntimeException($msg);
}
$source = $_GET['url'];
if ($source !== filter_var($source, \FILTER_SANITIZE_URL)) {
$msg = 'Passed url is invaid, url: ' . $source;
throw new \RuntimeException($msg);
}
if (filter_var($source, \FILTER_VALIDATE_URL) === FALSE) {
$msg = 'Passed url is invaid, url: ' . $source;
throw new \RuntimeException($msg);
}
$headers = get_headers($source, 1);
if (!is_array($headers)) {
$msg = 'Headers should be array but it is: ' . gettype($headers);
throw new \RuntimeException($msg);
}
$headers = array_change_key_case($headers, \CASE_LOWER);
if ( key_exists('content-security-policy', $headers) &&
isset($headers['content-security-policy'])
) {
$response = false;
}
elseif ( key_exists('x-frame-options', $headers) &&
(
strtoupper($headers['x-frame-options']) == 'DENY' ||
strtoupper($headers['x-frame-options']) == 'SAMEORIGIN'
)
) {
$response = false;
}
} catch (Exception $ex) {
$response = "Error: " . $ex->getMessage() . ' at: ' . $ex->getFile() . ':' . $ex->getLine();
}
$phpOutput = ob_get_clean();
if (!empty($phpOutput)) {
$response .= \PHP_EOL . 'PHP Output: ' . $phpOutput;
}
echo $response;
Using Throwable instead of Exception will also catch Errors in PHP7.
Keep in mind that:
$response = true;
echo $response; // prints "1"
but
$response = false;
echo $response; // prints ""
so for the $response = false you'll get an empty string, not 0
if you want to have 0 for false and 1 for true then change the $response = true; to $response = 1; for true and $response = false; to $response = 0; for false everywhere.
I hope that somehow helps

this php code works in localhost but not on server?

we are making an collage project that is about to store website name , category , and details so we are done with website and now we want to make app that will communicate with server through API . we had simple code like this in php script when data is added into database echo json_encode(true) . as android programmers know , retrofit library use key value pair type mechanism so we updated code with following.
<?php
$websiteName = $_POST['website_name'];
$websiteCategory = $_POST['website_cat'];
$websiteDetails = $_POST['website_details'];
try {
$pdo = new PDO('mysql:host=localhost;dbname=website' , 'root' , '');
$sql = 'INSERT INTO website_data SET website_name = :website_name , website_cat = :website_cat , website_details = :web_del';
$stmt = $pdo->prepare($sql);
$stmt->bindValue(':website_name' ,$websiteName);
$stmt->bindValue(':website_cat' ,$websiteCategory);
$stmt->bindValue(':web_del' ,$websiteDetails);
$stmt->execute();
echo json_encode(['response' => 'true']);
} catch (PDOException $e) {
$msg = $e->getMessage();
echo json_encode(['response' => $msg]);
}
?>
and here is javascript code that performs operation with ajax
function sendData(websiteName , categoryName , websiteDetails){
var params = 'website_name='+websiteName+'&website_cat='+categoryName+'&website_details='+websiteDetails;
var xml = new XMLHttpRequest();
xml.onreadystatechange = function(){
if(this.status == 200 && this.readyState == 4){
var response = this.responseText;
var responseJson = JSON.parse(response);
console.log('resonse from server' , responseJson['response']);
if(responseJson['response'] == 'true'){
addToCurrent(websiteName , categoryName , websiteDetails);
}else{
alert('unfortunatley data could not added succesfully');
}
} else{
console.log('there is some problem with sever');
}
}
xml.open('POST' , '../php/addNewWebsite.php' , true);
xml.setRequestHeader('Content-type' , 'application/x-www-form-urlencoded');
xml.send(params);
}
this is working as indented in localhost good but it is not working in our free server it shows the alert('unfortunatley data could not added succesfully');i do not know why does this happening. we have free server and domain from the awardspace.com
UPDATE
here is the error message i am getting from the server SQLSTATE[HY000] [2002] No such file or directory
Thank You .
I have encountered similiar issues in the past. You should try changing localhost to 127.0.0.1, assuming your MySQL server is running on the same box.
My belief is that the issue that you are encountering is that "localhost" uses a UNIX socket and can not find the database in the standard directory. However "127.0.0.1" uses TCP , which essentially means it runs through the "local internet" on the machine, being much more reliable than a UNIX socket.

PHP socket connections: read and send data in loop

I have to make a function, in which I send a packet to server and then read data. After a while I sometimes require to send a data to server again using the same socket (it's required that I use the same one).
For some reason second send, which is after read doesn't send data (it returns correct number (not false), but server doesn't receive packet). If I create new socket and send data - it works.
Here is an example:
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, '192.168.1.179', 1455);
socket_set_option($socket,SOL_SOCKET, SO_RCVTIMEO, array("sec"=>5, "usec"=>0));
$this->socket_functions->send_message($socket,$sendMsg,$funcName);
$tmp = trim($this->socket_functions->read_packet($socket));
for($i =0; $i<10; $i++)
{
$tmp = trim($this->socket_functions->read_packet($socket));
$this->socket_functions->send_message($socket, 'AAAA', $funcName); //doesn't work
/*
///works
$socket2 = $this->socket_functions->create_socket();
$this->socket_functions->send_message($socket2, 'AAAA', $funcName);
$this->socket_functions->disconnect($socket2);
*/
}
Function create_socket does the same as first 3 lines so the connection data is the same. I just brought it out so you are able to see my configuration.
For read and write I use functions socket_send() and socket_write().
Read packet function:
$resultMsg = "";
while(strlen($currentData = socket_read($socket,256))==256)
{
$resultMsg .=$currentData;
}
$resultMsg.=$currentData;
if(strlen($resultMsg)>1 && strpos($resultMsg,'<')>0)
{
$resultMsg = substr($resultMsg,strpos($resultMsg,'<'));
}
return $resultMsg;
Sending packet:
function create_packet($msg, $type)
{
$msg = $type.$this->convert_data->IntToAsciiChars(strlen($msg)).$msg;
$msg = chr(0).$this->convert_data->IntToAsciiChars(strlen($msg)).$msg;
return $msg;
}
function send_message($socket,$msg,$type)
{
$packet = $this->create_packet($msg,$type);
$res = socket_send($socket,$packet,strlen($packet),0);
if($res === false) return false;
return true;
}
EDIT
I did more testing and found out, that this only occurs, if the server, to which I'm connected keeps sending data. As in - the server sends multiple packets in row. If I try to send packet before the server has sent all of them, the packet isn't received. Does anyone knows why is this happening? I have desktop application, which does the same thing (sends data using the same socket while server is sending data), but it works there. Is there something specific?
I finally managed to fix this. After testing I found out, if I used send n+1 times to send the message, where n is amount of times read was called , I was able to send a message then.
I really don't know why this worked - maybe someone here knows?

Check if domain is available fails

I have been using this metode.
I have set it up on my site, but for some reason, it doesn't seems to work for all extensions.
As I set I did setup that code on my site, but modified it to check the requested domain name.
You can try it on my site here.
So here you can see some working examples:
try: just.com, just.net, example.com and test.com.
Some not working examples:
try: just.dk, example.dk and test.dk
Here is the complete code I have on the site:
<?php
function checkDomainAvailability($domain_name){
$server = 'whois.crsnic.net';
// Open a socket connection to the whois server
$connection = fsockopen($server, 43);
if (!$connection) return false;
// Send the requested doman name
fputs($connection, $domain_name."\r\n");
// Read and store the server response
$response_text = ' :';
while(!feof($connection)) {
$response_text .= fgets($connection,128);
}
// Close the connection
fclose($connection);
// Check the response stream whether the domain is available
if (strpos($response_text, 'No match for')) return true;
else return false;
}
$domainname = 'accurst.com';
if (isset($_GET['domain']))
$domainname = $_GET['domain'];
if(checkDomainAvailability($domainname)) echo 'Domain : '.$domainname.' is Available';
else echo 'Domain : '.$domainname.' is Already Taken';
?>
Does anyone have any idea how to fix this issue?
Probably because the whois server doesn't support those top level domains. Take a look at whomsy

Grabbing Twitter Friends Feed Using PHP and cURL

So in keeping with my last question, I'm working on scraping the friends feed from Twitter. I followed a tutorial to get this script written, pretty much step by step, so I'm not really sure what is wrong with it, and I'm not seeing any error messages. I've never really used cURL before save from the shell, and I'm extremely new to PHP so please bear with me.
<html>
<head>
<title>Twitcap</title>
</head>
<body>
<?php
function twitcap()
{
// Set your username and password
$user = 'osoleve';
$pass = '****';
// Set site in handler for cURL to download
$ch = curl_init("https://twitter.com/statuses/friends_timeline.xml");
// Set cURL's option
curl_setopt($ch,CURLOPT_HEADER,1); // We want to see the header
curl_setopt($ch,CURLOPT_TIMEOUT,30); // Set timeout to 30s
curl_setopt($ch,CURLOPT_USERPWD,$user.':'.$pass); // Set uname/pass
curl_setopt($ch,CURLOPT_RETURNTRANSER,1); // Do not send to screen
// For debugging purposes, comment when finished
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,0);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,0);
// Execute the cURL command
$result = curl_exec($ch);
// Remove the header
// We only want everything after <?
$data = strstr($result, '<?');
// Return the data
$xml = new SimpleXMLElement($data);
return $xml;
}
$xml = twitcap();
echo $xml->status[0]->text;
?>
</body>
</html>
Wouldn't you actually need everything after "?>" ?
$data = strstr($result,'?>');
Also, are you using a free web host? I once had an issue where my hosting provider blocked access to Twitter due to people spamming it.
note that if you use strstr the returend string will actually include the needle-string. so you have to strip of the first 2 chars from the string
i would rather recommend a combination of the function substr and strpos!
anways, i think simplexml should be able to handle this header meaning i think this step is not necessary!
furthermore if i open the url i don't see the like header! and if strstr doesnt find the string it returns false, so you dont have any data in your current script
instead of $data = strstr($result, '<?'); try this:
if(strpos('?>',$data) !== false) {
$data = strstr($result, '?>');
} else {
$data = $result;
}

Categories