Plesk api String could not be parsed as XML - php

I want to use the Plesk Api for PHP. I download a sample from the Parallels website and tried to use it for my website. When I open the page on my website I get the following error:
Fatal error: Uncaught exception 'Exception' with message 'String could not be parsed as XML
The code I use:
<?php
error_reporting(E_ALL);
ini_set("display_errors", 1);
/**
* Reports error during API RPC request
*/
class ApiRequestException extends Exception {}
/**
* Returns DOM object representing request for information about all available domains
* #return DOMDocument
*/
function domainsInfoRequest()
{
$xmldoc = new DomDocument('1.0', 'UTF-8');
$xmldoc->formatOutput = true;
// <packet>
$packet = $xmldoc->createElement('packet');
$packet->setAttribute('version', '1.4.1.2');
$xmldoc->appendChild($packet);
// <packet/domain>
$domain = $xmldoc->createElement('domain');
$packet->appendChild($domain);
// <packet/domain/get>
$get = $xmldoc->createElement('get');
$domain->appendChild($get);
// <packet/domain/get/filter>
$filter = $xmldoc->createElement('filter');
$get->appendChild($filter);
// <packet/domain/get/dataset>
$dataset = $xmldoc->createElement('dataset');
$get->appendChild($dataset);
// dataset elements
$dataset->appendChild($xmldoc->createElement('limits'));
$dataset->appendChild($xmldoc->createElement('prefs'));
$dataset->appendChild($xmldoc->createElement('user'));
$dataset->appendChild($xmldoc->createElement('hosting'));
$dataset->appendChild($xmldoc->createElement('stat'));
$dataset->appendChild($xmldoc->createElement('gen_info'));
return $xmldoc;
}
/**
* Prepares CURL to perform Plesk API request
* #return resource
*/
function curlInit($host, $login, $password)
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, "https://{$host}:8443/enterprise/control/agent.php");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_HTTPHEADER,
array("HTTP_AUTH_LOGIN: {$login}",
"HTTP_AUTH_PASSWD: {$password}",
"HTTP_PRETTY_PRINT: TRUE",
"Content-Type: text/xml")
);
return $curl;
}
/**
* Performs a Plesk API request, returns raw API response text
*
* #return string
* #throws ApiRequestException
*/
function sendRequest($curl, $packet)
{
curl_setopt($curl, CURLOPT_POSTFIELDS, $packet);
$result = curl_exec($curl);
if (curl_errno($curl)) {
$errmsg = curl_error($curl);
$errcode = curl_errno($curl);
curl_close($curl);
throw new ApiRequestException($errmsg, $errcode);
}
curl_close($curl);
return $result;
}
/**
* Looks if API responded with correct data
*
* #return SimpleXMLElement
* #throws ApiRequestException
*/
function parseResponse($response_string)
{
$xml = new SimpleXMLElement($response_string);
if (!is_a($xml, 'SimpleXMLElement'))
throw new ApiRequestException("Can not parse server response: {$response_string}");
return $xml;
}
/**
* Check data in API response
* #return void
* #throws ApiRequestException
*/
function checkResponse(SimpleXMLElement $response)
{
$resultNode = $response->domain->get->result;
// check if request was successful
if ('error' == (string)$resultNode->status)
throw new ApiRequestException("Plesk API returned error: " . (string)$resultNode->result->errtext);
}
//
// int main()
//
$host = '************';
$login = '************';
$password = '************';
$curl = curlInit($host, $login, $password);
try {
$response = sendRequest($curl, domainsInfoRequest()->saveXML());
$responseXml = parseResponse($response);
checkResponse($responseXml);
} catch (ApiRequestException $e) {
echo $e;
die();
}
// Explore the result
foreach ($responseXml->xpath('/packet/domain/get/result') as $resultNode) {
echo "Domain id: " . (string)$resultNode->id . " ";
echo (string)$resultNode->data->gen_info->name . " (" . (string)$resultNode->data->gen_info->dns_ip_address . ")\n";
}
?>
I hope someone can help me to find a solution.

Your script works perfectly with my server (as much as I was able to restore the formatting).
It seems based on the example provided in original Parallels documentation. So I have grabbed an example from `Plesk integration guide and applied to my server - it works as well.
I could assume some misconfiguration of your Plesk server. Perhaps you could troubleshoot it if your print XML request (domainsInfoRequest()->saveXML()) and XML response ($response). For some reason apparently your $response contains something different from a valid XML code. If not sure, you can copy/paste it into a file and run xmllint (XML validation tool) on it.

Related

Can't do anything after receiving Paypal IPN

I am using Paypal's two IPN scripts from github here: https://github.com/paypal/ipn-code-samples/tree/master/php however they aren't working.
I send the test IPN using Paypal's tool here: https://developer.paypal.com/developer/ipnSimulator/ and it says it was succesful: "IPN was sent and the handshake was verified."
However, I can't do what I want after that. I've tried inserting into a database or even just sending a success email. Both of these work fine when done on their own but when I add it to the IPN script nothing happens.
PaypalIPN.php (copied from the github)
<?php
class PaypalIPN
{
/** #var bool Indicates if the sandbox endpoint is used. */
private $use_sandbox = false;
/** #var bool Indicates if the local certificates are used. */
private $use_local_certs = true;
/** Production Postback URL */
const VERIFY_URI = 'https://ipnpb.paypal.com/cgi-bin/webscr';
/** Sandbox Postback URL */
const SANDBOX_VERIFY_URI = 'https://ipnpb.sandbox.paypal.com/cgi- bin/webscr';
/** Response from PayPal indicating validation was successful */
const VALID = 'VERIFIED';
/** Response from PayPal indicating validation failed */
const INVALID = 'INVALID';
/**
* Sets the IPN verification to sandbox mode (for use when testing,
* should not be enabled in production).
* #return void
*/
public function useSandbox()
{
$this->use_sandbox = true;
}
/**
* Sets curl to use php curl's built in certs (may be required in some
* environments).
* #return void
*/
public function usePHPCerts()
{
$this->use_local_certs = false;
}
/**
* Determine endpoint to post the verification data to.
*
* #return string
*/
public function getPaypalUri()
{
if ($this->use_sandbox) {
return self::SANDBOX_VERIFY_URI;
} else {
return self::VERIFY_URI;
}
}
/**
* Verification Function
* Sends the incoming post data back to PayPal using the cURL library.
*
* #return bool
* #throws Exception
*/
public function verifyIPN()
{
if ( ! count($_POST)) {
throw new Exception("Missing POST Data");
}
$raw_post_data = file_get_contents('php://input');
$raw_post_array = explode('&', $raw_post_data);
$myPost = array();
foreach ($raw_post_array as $keyval) {
$keyval = explode('=', $keyval);
if (count($keyval) == 2) {
// Since we do not want the plus in the datetime string to be encoded to a space, we manually encode it.
if ($keyval[0] === 'payment_date') {
if (substr_count($keyval[1], '+') === 1) {
$keyval[1] = str_replace('+', '%2B', $keyval[1]);
}
}
$myPost[$keyval[0]] = urldecode($keyval[1]);
}
}
// Build the body of the verification post request, adding the _notify-validate command.
$req = 'cmd=_notify-validate';
$get_magic_quotes_exists = false;
if (function_exists('get_magic_quotes_gpc')) {
$get_magic_quotes_exists = true;
}
foreach ($myPost as $key => $value) {
if ($get_magic_quotes_exists == true && get_magic_quotes_gpc() == 1)
{
$value = urlencode(stripslashes($value));
} else {
$value = urlencode($value);
}
$req .= "&$key=$value";
}
// Post the data back to PayPal, using curl. Throw exceptions if errors occur.
$ch = curl_init($this->getPaypalUri());
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
curl_setopt($ch, CURLOPT_SSLVERSION, 6);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
// This is often required if the server is missing a global cert bundle, or is using an outdated one.
if ($this->use_local_certs) {
curl_setopt($ch, CURLOPT_CAINFO, __DIR__ . "/cert/cacert.pem");
}
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'User-Agent: PHP-IPN-Verification-Script',
'Connection: Close',
));
$res = curl_exec($ch);
if ( ! ($res)) {
$errno = curl_errno($ch);
$errstr = curl_error($ch);
curl_close($ch);
throw new Exception("cURL error: [$errno] $errstr");
}
$info = curl_getinfo($ch);
$http_code = $info['http_code'];
if ($http_code != 200) {
throw new Exception("PayPal responded with http code $http_code");
}
curl_close($ch);
// Check if PayPal verifies the IPN data, and if so, return true.
if ($res == self::VALID) {
return true;
} else {
return false;
}
}
}
This is my IPN handler URL, example_usage.php (also copied from the github, I just added the one line to send an email, which does nothing when I send the test IPN):
<?php namespace Listener;
require('PaypalIPN.php');
use PaypalIPN;
$ipn = new PaypalIPN();
// Use the sandbox endpoint during testing.
$ipn->useSandbox();
$verified = $ipn->verifyIPN();
if ($verified) {
/*
* Process IPN
* A list of variables is available here:
*
https://developer.paypal.com/webapps/developer/docs/classic/ipn/integration-
guide/IPNandPDTVariables/
*/
//THIS IS THE ONLY PART I HAVE ADDED, BUT NOTHING IS HAPPENING
$name = '' //Get name from form input
$email = '' //Get email from form input
$amount = '' //Get amount from hidden form input
$subject = 'New order from' . $name
$message = 'New order. Amount: ' . $amount
//For some reason this isn't being sent, even if I change $subject and $message to my own string.
$sendemail= mail("***#***.com", $subject, $message);
}
// Reply with an empty 200 response to indicate to paypal the IPN was
received correctly.
header("HTTP/1.1 200 OK");
?>
Does anyone have an idea of what the problem is? Thanks if so
You need to make sure the IPNs are triggering as expected, and are being sent to the URL you expect.
Follow the steps outlined here and you'll be able to find the problem, which includes:
Local Testing
IPN Simulator
Sandbox Transaction Testing
Deployment
Additional tips for troubleshooting.

Paypal Missing POST Data

I'm using the regular files from Paypal
THIS IS ZZZ.php
<?php namespace Listener;
require('PaypalIPN.php');
use PaypalIPN;
$ipn = new PaypalIPN();
// Use the sandbox endpoint during testing.
$ipn->useSandbox();
$verified = $ipn->verifyIPN();
if ($verified) {
$response = "verified";
file_put_contents("test.txt", $response);
/*
* Process IPN
* A list of variables is available here:
* https://developer.paypal.com/webapps/developer/docs/classic/ipn/integration-guide/IPNandPDTVariables/
*/
}
header("HTTP/1.1 200 OK");
THIS IS PAYPALIPN.php (regular one from them)
class PaypalIPN
{
/**
* #var bool $use_sandbox Indicates if the sandbox endpoint is used.
*/
private $use_sandbox = false;
/**
* #var bool $use_local_certs Indicates if the local certificates are used.
*/
private $use_local_certs = true;
/** Production Postback URL */
const VERIFY_URI = 'https://ipnpb.paypal.com/cgi-bin/webscr';
/** Sandbox Postback URL */
const SANDBOX_VERIFY_URI = 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr';
/** Response from PayPal indicating validation was successful */
const VALID = 'VERIFIED';
/** Response from PayPal indicating validation failed */
const INVALID = 'INVALID';
/**
* Sets the IPN verification to sandbox mode (for use when testing,
* should not be enabled in production).
* #return void
*/
public function useSandbox()
{
$this->use_sandbox = true;
}
/**
* Sets curl to use php curl's built in certs (may be required in some
* environments).
* #return void
*/
public function usePHPCerts()
{
$this->use_local_certs = false;
}
/**
* Determine endpoint to post the verification data to.
* #return string
*/
public function getPaypalUri()
{
if ($this->use_sandbox) {
return self::SANDBOX_VERIFY_URI;
} else {
return self::VERIFY_URI;
}
}
/**
* Verification Function
* Sends the incoming post data back to PayPal using the cURL library.
*
* #return bool
* #throws Exception
*/
public function verifyIPN()
{
if ( ! count($_POST)) {
throw new Exception("Missing POST Data");
}
$raw_post_data = file_get_contents('php://input');
$raw_post_array = explode('&', $raw_post_data);
$myPost = array();
foreach ($raw_post_array as $keyval) {
$keyval = explode('=', $keyval);
if (count($keyval) == 2) {
// Since we do not want the plus in the datetime string to be encoded to a space, we manually encode it.
if ($keyval[0] === 'payment_date') {
if (substr_count($keyval[1], '+') === 1) {
$keyval[1] = str_replace('+', '%2B', $keyval[1]);
}
}
$myPost[$keyval[0]] = urldecode($keyval[1]);
}
}
// Build the body of the verification post request, adding the _notify-validate command.
$req = 'cmd=_notify-validate';
$get_magic_quotes_exists = false;
if (function_exists('get_magic_quotes_gpc')) {
$get_magic_quotes_exists = true;
}
foreach ($myPost as $key => $value) {
if ($get_magic_quotes_exists == true && get_magic_quotes_gpc() == 1) {
$value = urlencode(stripslashes($value));
} else {
$value = urlencode($value);
}
$req .= "&$key=$value";
}
// Post the data back to PayPal, using curl. Throw exceptions if errors occur.
$ch = curl_init($this->getPaypalUri());
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
curl_setopt($ch, CURLOPT_SSLVERSION, 6);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
// This is often required if the server is missing a global cert bundle, or is using an outdated one.
if ($this->use_local_certs) {
curl_setopt($ch, CURLOPT_CAINFO, __DIR__ . "/cert/cacert.pem");
}
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close'));
$res = curl_exec($ch);
if ( ! ($res)) {
$errno = curl_errno($ch);
$errstr = curl_error($ch);
curl_close($ch);
throw new Exception("cURL error: [$errno] $errstr");
}
$info = curl_getinfo($ch);
$http_code = $info['http_code'];
if ($http_code != 200) {
throw new Exception("PayPal responded with http code $http_code");
}
curl_close($ch);
// Check if PayPal verifies the IPN data, and if so, return true.
if ($res == self::VALID) {
return true;
} else {
return false;
}
}
}
I'm receving a message at the error log of my server that says:
[25-Feb-2018 16:46:49 UTC] PHP Fatal error: Uncaught exception 'Exception' with message 'Missing POST Data' in /home2/laplatas/public_html/php/PaypalIPN.php:72
Stack trace:
#0 /home2/laplatas/public_html/php/zzz.php(11): PaypalIPN->verifyIPN()
#1 {main}
thrown in /home2/laplatas/public_html/php/PaypalIPN.php on line 72
[25-Feb-2018 16:47:44 UTC] PHP Fatal error: Uncaught exception 'Exception' with message 'Missing POST Data' in /home2/laplatas/public_html/php/PaypalIPN.php:72
Stack trace:
#0 /home2/laplatas/public_html/php/zzz.php(11): PaypalIPN->verifyIPN()
#1 {main}
thrown in /home2/laplatas/public_html/php/PaypalIPN.php on line 72
I have tryed everything but no success, I have readed also that could be that my server is not allowing post requests properly but it's the first issue I know about that, and if so, How do I change these file to allow post requests?
I have also open a question in paypal community... the issue is common but nobody answers properly
https://www.paypal-community.com/t5/IPN-PDT/Missing-POST-Data/m-p/1448349#M153
THANKS A LOT TO #Athrun Zara & #rtfm. I'VE GOT THE SOLUTION!!!!
If you find yourself with this issue, just check on your web server if they have dissabled the EMPTY post request, that's what was blocking the whole thing, not programming issues. The thing is that Paypal firsts checks if the adress is real with an empty call, that your web server will reject.
It's been more than 10 hours of work to the bin...well I have learn the whole process as an expert and open an unexisting and unkwon issue in every programming website.

PayPal IPN Always Returns "INVALID"

My problem
I set up an IPN listener in PHP, but it always returns INAVLID when testing with PayPal's IPN Simulator.
I know that this is a frequently asked question, but I have spent an entire weekend reading 50+ similar questions and trying out their solutions, but not a single one of them worked for me.
Note: I have to use fsock, my server does not support cURL.
What I tried
Ensured that my server is sending the request to www.sandbox.paypal.com and not www.paypal.com.
Ensured that my server uses SSL and port 443.
Ensured that the Host header is not missing.
Ensured that my response is equal to PayPal's request, prefixed with cmd=_notify-validate&.
Ensured that my server is parsing the VERIFIED / INVALID response correctly (PayPal's new system sends 7\r\nINVALID\r\n0 instead of just INVALID).
My code
IPN listener class
<?php
/**
* PayPal IPN Listener
*
* A class to listen for and handle Instant Payment Notifications (IPN) from
* the PayPal server.
*
* Forked from the great Quixotix PayPal IPN script. This fork plans to
* fix the current issues with the original repo, as well as update the code
* for use according to PayPal's documentation, and today's standards.
*
* #package PHP-PayPal-IPN
* #link https://github.com/WadeShuler/PHP-PayPal-IPN
* #forked https://github.com/Quixotix/PHP-PayPal-IPN
* #author Wade Shuler
* #copyright Copyright (c) 2015, Wade Shuler
* #license http://choosealicense.com/licenses/gpl-2.0/
* #version 2.5.2
*/
class IpnListener
{
/**
* If true, the recommended cURL PHP library is used to send the post back
* to PayPal. If flase then fsockopen() is used. Default true.
*
* #var boolean
*/
public $use_curl = true;
/**
* If true, cURL will use the CURLOPT_FOLLOWLOCATION to follow any
* "Location: ..." headers in the response.
*
* #var boolean
*/
public $follow_location = false;
/**
* If true, the paypal sandbox URI www.sandbox.paypal.com is used for the
* post back. If false, the live URI www.paypal.com is used. Default false.
*
* #var boolean
*/
public $use_sandbox = false;
/**
* The amount of time, in seconds, to wait for the PayPal server to respond
* before timing out. Default 30 seconds.
*
* #var int
*/
public $timeout = 30;
/**
* If true, enable SSL certification validation when using cURL
*
* #var boolean
*/
public $verify_ssl = true;
private $_errors = array();
private $post_data;
private $rawPostData; // raw data from php://input
private $post_uri = '';
private $response_status = '';
private $response = '';
const PAYPAL_HOST = 'www.paypal.com';
const SANDBOX_HOST = 'www.sandbox.paypal.com';
/**
* Post Back Using cURL
*
* Sends the post back to PayPal using the cURL library. Called by
* the processIpn() method if the use_curl property is true. Throws an
* exception if the post fails. Populates the response, response_status,
* and post_uri properties on success.
*
* #todo add URL param so function is more dynamic
*
* #param string The post data as a URL encoded string
*/
protected function curlPost($encoded_data)
{
$uri = 'https://'.$this->getPaypalHost().'/cgi-bin/webscr';
$this->post_uri = $uri;
$ch = curl_init();
if ($this->verify_ssl) {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_CAINFO, dirname(dirname(__FILE__)) . '/cert/api_cert_chain.crt');
}
curl_setopt($ch, CURLOPT_URL, $uri);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $encoded_data);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $this->follow_location);
curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
$this->response = curl_exec($ch);
$this->response_status = strval(curl_getinfo($ch, CURLINFO_HTTP_CODE));
if ($this->response === false || $this->response_status == '0') {
$errno = curl_errno($ch);
$errstr = curl_error($ch);
throw new Exception("cURL error: [$errno] $errstr");
}
return $this->response;
}
/**
* Post Back Using fsockopen()
*
* Sends the post back to PayPal using the fsockopen() function. Called by
* the processIpn() method if the use_curl property is false. Throws an
* exception if the post fails. Populates the response, response_status,
* and post_uri properties on success.
*
* #todo add URL param so function is more dynamic
*
* #param string The post data as a URL encoded string
*/
protected function fsockPost($encoded_data)
{
$uri = 'ssl://'.$this->getPaypalHost();
$port = '443';
$this->post_uri = $uri.'/cgi-bin/webscr';
$fp = fsockopen($uri, $port, $errno, $errstr, $this->timeout);
if (!$fp) {
// fsockopen error
throw new Exception("fsockopen error: [$errno] $errstr");
}
$header = "POST /cgi-bin/webscr HTTP/1.1\r\n";
$header .= "Host: ".$this->getPaypalHost()."\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: ".strlen($encoded_data)."\r\n";
$header .= "Connection: Close\r\n\r\n";
fputs($fp, $header.$encoded_data."\r\n\r\n");
while(!feof($fp)) {
if (empty($this->response)) {
// extract HTTP status from first line
$this->response .= $status = fgets($fp, 1024);
$this->response_status = trim(substr($status, 9, 4));
} else {
$this->response .= fgets($fp, 1024);
}
}
fclose($fp);
return $this->response;
}
private function getPaypalHost()
{
return ($this->use_sandbox) ? self::SANDBOX_HOST : self::PAYPAL_HOST;
}
public function getErrors()
{
return $this->_errors;
}
private function addError($error)
{
$this->_errors[] .= $error;
}
public function getPostData()
{
return $this->post_data;
}
public function getRawPostData()
{
return $this->rawPostData;
}
/**
* Get POST URI
*
* Returns the URI that was used to send the post back to PayPal. This can
* be useful for troubleshooting connection problems. The default URI
* would be "ssl://www.sandbox.paypal.com:443/cgi-bin/webscr"
*
* #return string
*/
public function getPostUri()
{
return $this->post_uri;
}
/**
* Get Response
*
* Returns the entire response from PayPal as a string including all the
* HTTP headers.
*
* #return string
*/
public function getResponse()
{
return $this->response;
}
/**
* Get Response Status
*
* Returns the HTTP response status code from PayPal. This should be "200"
* if the post back was successful.
*
* #return string
*/
public function getResponseStatus()
{
return $this->response_status;
}
/**
* Get Text Report
*
* Returns a report of the IPN transaction in plain text format. This is
* useful in emails to order processors and system administrators. Override
* this method in your own class to customize the report.
*
* #return string
*/
public function getTextReport()
{
$r = '';
// date and POST url
for ($i=0; $i<80; $i++) { $r .= '-'; }
$r .= "\n[".date('m/d/Y g:i A').'] - '.$this->getPostUri();
if ($this->use_curl) {
$r .= " (curl)\n";
} else {
$r .= " (fsockopen)\n";
}
// HTTP Response
for ($i=0; $i<80; $i++) { $r .= '-'; }
$r .= "\n{$this->getResponse()}\n";
// POST vars
for ($i=0; $i<80; $i++) { $r .= '-'; }
$r .= "\n";
foreach ($this->post_data as $key => $value) {
$r .= str_pad($key, 25)."$value\n";
}
$r .= "\n\n";
return $r;
}
/**
* Process IPN
*
* Handles the IPN post back to PayPal and parsing the response. Call this
* method from your IPN listener script. Returns true if the response came
* back as "VERIFIED", false if the response came back "INVALID", and
* throws an exception if there is an error.
*
* #param array
*
* #return boolean
*/
public function processIpn($post_data=null)
{
try
{
$this->requirePostMethod(); // processIpn() should check itself if data is POST
// Read POST data
// reading posted data directly from $_POST causes serialization
// issues with array data in POST. Reading raw POST data from input stream instead.
if ($post_data === null) {
$raw_post_data = file_get_contents('php://input');
} else {
$raw_post_data = $post_data;
}
$this->rawPostData = $raw_post_data; // set raw post data for Class use
// if post_data is php input stream, make it an array.
if ( ! is_array($raw_post_data) ) {
$raw_post_array = explode('&', $raw_post_data);
$this->post_data = $raw_post_array; // use post array because it's same as $_POST
} else {
$this->post_data = $raw_post_data; // use post array because it's same as $_POST
}
$myPost = array();
if (isset($raw_post_array)) {
foreach ($raw_post_array as $keyval) {
$keyval = explode('=', $keyval);
if (count($keyval) == 2) {
$myPost[$keyval[0]] = urldecode($keyval[1]);
}
}
}
// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';
foreach ($myPost as $key => $value) {
if (function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc() == 1) {
$value = urlencode(stripslashes($value));
} else {
$value = urlencode($value);
}
$req .= "&$key=$value";
}
//XXX Debug log
$file = fopen('lastresponse.log', 'w');
fwrite($file, $req);
fclose($file);
if ($this->use_curl) {
$res = $this->curlPost($req);
} else {
$res = $this->fsockPost($req);
}
if (strpos($res, '200') === false) {
throw new Exception("Invalid response status: " . $res);
}
// Split response headers and payload, a better way for strcmp
$tokens = explode("\r\n\r\n", trim($res));
$res = trim(end($tokens));
if (strpos ($res, "VERIFIED") !== false) {
return true;
} else if (strpos ($res, "INVALID") !== false) {
return false;
} else {
throw new Exception("Unexpected response from PayPal: " . $res);
}
} catch (Exception $e) {
$this->addError($e->getMessage());
return false;
}
return false;
}
/**
* Require Post Method
*
* Throws an exception and sets a HTTP 405 response header if the request
* method was not POST.
*/
public function requirePostMethod()
{
// require POST requests
if ($_SERVER['REQUEST_METHOD'] && $_SERVER['REQUEST_METHOD'] != 'POST') {
header('Allow: POST', true, 405);
throw new Exception("Invalid HTTP request method.");
}
}
}
Actual IPN listener
<?php
ini_set("log_errors", 1);
ini_set("error_log", "php-error.log");
$file = fopen('lastrequest.log', 'w');
fwrite($file, file_get_contents('php://input'));
fclose($file);
require_once $_SERVER['DOCUMENT_ROOT'] . '/_includes/ipnlistener.php';
$listener = new IpnListener();
$listener->use_sandbox = true;
$listener->use_curl = false;
header('HTTP/1.1 200 OK');
if ($verified = $listener->processIpn())
{
// Valid IPN
/*
1. Check that $_POST['payment_status'] is "Completed"
2. Check that $_POST['txn_id'] has not been previously processed
3. Check that $_POST['receiver_email'] is your Primary PayPal email
4. Check that $_POST['payment_amount'] and $_POST['payment_currency'] are correct
*/
$transactionRawData = $listener->getRawPostData(); // raw data from PHP input stream
$transactionData = $listener->getPostData(); // POST data array
// Feel free to modify path and filename. Make SURE THE DIRECTORY IS WRITEABLE!
// For security reasons, you should use a path above/outside of your webroot
file_put_contents('ipn_success.log', print_r($transactionData, true) . PHP_EOL, LOCK_EX | FILE_APPEND);
} else {
// Invalid IPN
$errors = $listener->getErrors();
// Feel free to modify path and filename. Make SURE THE DIRECTORY IS WRITEABLE!
// For security reasons, you should use a path above/outside of your webroot
file_put_contents('ipn_errors.log', print_r($errors, true) . PHP_EOL, LOCK_EX | FILE_APPEND);
}
file_put_contents("verified.log", $verified ? "VERIFIED" : "INVALID");
My logs
PayPal's request
payment_type=instant&payment_date=Sun%20Dec%2006%202015%2020%3A05%3A21%20GMT%2B0100%20%28Mitteleurop%C3%A4ische%20Zeit%29&payment_status=Completed&address_status=confirmed&payer_status=verified&first_name=John&last_name=Smith&payer_email=buyer%40paypalsandbox.com&payer_id=TESTBUYERID01&address_name=John%20Smith&address_country=United%20States&address_country_code=US&address_zip=95131&address_state=CA&address_city=San%20Jose&address_street=123%20any%20street&business=seller%40paypalsandbox.com&receiver_email=seller%40paypalsandbox.com&receiver_id=seller%40paypalsandbox.com&residence_country=US&item_name1=something&item_number1=AK-1234&tax=2.02&mc_currency=USD&mc_fee=0.44&mc_gross=12.34&mc_gross1=12.34&mc_handling=2.06&mc_handling1=1.67&mc_shipping=3.02&mc_shipping1=1.02&txn_type=cart&txn_id=936522821&notify_version=2.1&custom=xyz123&invoice=abc1234&test_ipn=1&verify_sign=AFcWxV21C7fd0v3bYYYRCpSSRl31A61b6KnaHJWRwuKxRGWvWo2Bos20
My server's response
cmd=_notify-validate&payment_type=instant&payment_date=Sun+Dec+06+2015+20%3A05%3A21+GMT%2B0100+%28Mitteleurop%C3%A4ische+Zeit%29&payment_status=Completed&address_status=confirmed&payer_status=verified&first_name=John&last_name=Smith&payer_email=buyer%40paypalsandbox.com&payer_id=TESTBUYERID01&address_name=John+Smith&address_country=United+States&address_country_code=US&address_zip=95131&address_state=CA&address_city=San+Jose&address_street=123+any+street&business=seller%40paypalsandbox.com&receiver_email=seller%40paypalsandbox.com&receiver_id=seller%40paypalsandbox.com&residence_country=US&item_name1=something&item_number1=AK-1234&tax=2.02&mc_currency=USD&mc_fee=0.44&mc_gross=12.34&mc_gross1=12.34&mc_handling=2.06&mc_handling1=1.67&mc_shipping=3.02&mc_shipping1=1.02&txn_type=cart&txn_id=936522821&notify_version=2.1&custom=xyz123&invoice=abc1234&test_ipn=1&verify_sign=AFcWxV21C7fd0v3bYYYRCpSSRl31A61b6KnaHJWRwuKxRGWvWo2Bos20
I've spent almost 2 days on this issue and thought I would share with people what have worked for me hopefully It can help a few others who faced the same issue.
Problem
PayPal IPN simulator gives INVALID IPN response always.
Solution
When simulating change the payment_date in simulator fields to NULL and everything should start working if your setup is correct.
IPN Simulator uses Sandbox environment, but your IPN Listener class is setting to public $use_sandbox = false;, that means you are in Live environment, which could be the cause of the issue of your response always getting INVALID.

Get direct link videos from Vimeo in PHP

I want a direct link to videos from Vimeo with a PHP script.
I managed to find them manually, but my PHP script does not work.
Here is the initiative:
For example I took this video: http://vimeo.com/22439234
When you go on the page, Vimeo generates a signature associated with the current timestamp and this video. This information is stored in a JavaScript variable, around line 520 just after:
window.addEvent ('domready', function () {
Then when you click Play, the HTML5 player reads this variable and sends an HTTP request:
http:// player.vimeo.com/play_redirect?clip_id=37111719&sig={SIGNATURE}&time={TIMESTAMP}&quality=sd&codecs=H264,VP8,VP6&type=moogaloop_local&embed_location=
But it also works with:
http:// player.vimeo.com/play_redirect?clip_id=37111719&sig={SIGNATURE}&time={TIMESTAMP}&quality=sd
If this URL does not open with the IP address that opened http://vimeo.com/22439234, this returns the HTTP code 200 with an error message.
If this URL is opened with the correct IP address, the header "Location" redirects to link to the video file:
http://av.vimeo.com/XXX/XX/XXXX.mp4?aksessionid=XXXX&token=XXXXX_XXXXXXXXX
When I build this link http://player.vimeo.com/play_redirect?... manually ("right click"> "source code"> "line 520") it works.
But with PHP and regex it returns the HTTP code 200 with an error message.
Why ?
From my observations, Vimeo does not check the headers of the HTTP request for http:// player.vimeo.com/play_redirect?...
GET, HEAD, with cookies, without cookies, referrer etc. ... does not change.
With PHP, I use the function file_get_contents() and get_headers().
<?php
function getVimeo($id) {
$content = file_get_contents('http://vimeo.com/'.$id);
if (preg_match('#document\.getElementById\(\'player_(.+)\n#i', $content, $scriptBlock) == 0)
return 1;
preg_match('#"timestamp":([0-9]+)#i', $scriptBlock[1], $matches);
$timestamp = $matches[1];
preg_match('#"signature":"([a-z0-9]+)"#i', $scriptBlock[1], $matches);
$signature = $matches[1];
$url = 'http://player.vimeo.com/play_redirect?clip_id='.$id.'&sig='.$signature.'&time='.$timestamp.'&quality=sd';
print_r(get_headers($url, 1));
}
The algorithm looks like this:
Input data: vimeoUrl.
content = getRemoteContent(vimeoUrl).
Parse content to find and extract the value from data-config-url
attribute.
Navigate to data-config-url and load the content as JSON Object:
$video = json_decode($this->getRemoteContent($video->getAttribute('data-config-url')));
Return $video->request->files->h264->sd->url — this will return a
direct link for SD quality video.
Here is my simple class, that working for this moment.
class VideoController
{
/**
* #var array Vimeo video quality priority
*/
public $vimeoQualityPrioritet = array('sd', 'hd', 'mobile');
/**
* #var string Vimeo video codec priority
*/
public $vimeoVideoCodec = 'h264';
/**
* Get direct URL to Vimeo video file
*
* #param string $url to video on Vimeo
* #return string file URL
*/
public function getVimeoDirectUrl($url)
{
$result = '';
$videoInfo = $this->getVimeoVideoInfo($url);
if ($videoInfo && $videoObject = $this->getVimeoQualityVideo($videoInfo->request->files))
{
$result = $videoObject->url;
}
return $result;
}
/**
* Get Vimeo video info
*
* #param string $url to video on Vimeo
* #return \stdClass|null result
*/
public function getVimeoVideoInfo($url)
{
$videoInfo = null;
$page = $this->getRemoteContent($url);
$dom = new \DOMDocument("1.0", "utf-8");
libxml_use_internal_errors(true);
$dom->loadHTML('<?xml version="1.0" encoding="UTF-8"?>' . "\n" . $page);
$xPath = new \DOMXpath($dom);
$video = $xPath->query('//div[#data-config-url]');
if ($video)
{
$videoObj = json_decode($this->getRemoteContent($video->item(0)->getAttribute('data-config-url')));
if (!property_exists($videoObj, 'message'))
{
$videoInfo = $videoObj;
}
}
return $videoInfo;
}
/**
* Get vimeo video object
*
* #param stdClass $files object of Vimeo files
* #return stdClass Video file object
*/
public function getVimeoQualityVideo($files)
{
$video = null;
if (!property_exists($files, $this->vimeoVideoCodec) && count($files->codecs))
{
$this->vimeoVideoCodec = array_shift($files->codecs);
}
$codecFiles = $files->{$this->vimeoVideoCodec};
foreach ($this->vimeoQualityPrioritet as $quality)
{
if (property_exists($codecFiles, $quality))
{
$video = $codecFiles->{$quality};
break;
}
}
if (!$video)
{
foreach (get_object_vars($codecFiles) as $file)
{
$video = $file;
break;
}
}
return $video;
}
/**
* Get remote content by URL
*
* #param string $url remote page URL
* #return string result content
*/
public function getRemoteContent($url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_TIMEOUT, 20);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
curl_setopt($ch, CURLOPT_USERAGENT, 'spider');
$content = curl_exec($ch);
curl_close($ch);
return $content;
}
}
Using:
$video = new VideoController;
var_dump($video->getVimeoDirectUrl('http://vimeo.com/90747156'));
Try add a valid user-agent to headers for an each request.
For this you must use cURL or HttpRequest instead file_get_contents().
After such manipulations I got a working link for downloading the video file.
Here my code:
function getVimeo($id) {
// get page with a player
$queryResult = httpQuery('http://vimeo.com/' . $id);
$content = $queryResult['content'];
if (preg_match('#document\.getElementById\(\'player_(.+)\n#i', $content, $scriptBlock) == 0)
return 1;
preg_match('#"timestamp":([0-9]+)#i', $scriptBlock[1], $matches);
$timestamp = $matches[1];
preg_match('#"signature":"([a-z0-9]+)"#i', $scriptBlock[1], $matches);
$signature = $matches[1];
$url = 'http://player.vimeo.com/play_redirect?clip_id=' . $id . '&sig=' . $signature . '&time=' . $timestamp . '&quality=sd';
// make the request for getting a video url
#print_r(get_headers($url, 1));
$finalQuery = httpQuery($url);
return $finalQuery['redirect_url'];
}
// make queries via CURL
function httpQuery($url) {
$options = array(
CURLOPT_USERAGENT => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.19 (KHTML, like Gecko) Ubuntu/12.04 Chromium/18.0.1025.168 Chrome/18.0.1025.168 Safari/535.19',
CURLOPT_RETURNTRANSFER => true,
);
$ch = curl_init($url);
curl_setopt_array($ch, $options);
$content = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
$result = $info;
$result['content'] = $content;
return $result;
}
echo getVimeo(22439234);

Gotomeeting php api(oauth) implementation

I am trying to create a php gotomeating api implementation. I successfully got the access_token but for any other requests I get error responses. This is my code:
<?php
session_start();
$key = '#';
$secret = '#';
$domain = $_SERVER['HTTP_HOST'];
$base = "/oauth/index.php";
$base_url = urlencode("http://$domain$base");
$OAuth_url = "https://api.citrixonline.com/oauth/authorize?client_id=$key&redirect_uri=$base_url";
$OAuth_exchange_keys_url = "http://api.citrixonline.com/oauth/access_token?grant_type=authorization_code&code={responseKey}&client_id=$key";
if($_SESSION['access_token']) CreateForm();else
if($_GET['send']) OAuth_Authentication($OAuth_url);
elseif($_GET['code']) OAuth_Exchanging_Response_Key($_GET['code'],$OAuth_exchange_keys_url);
function OAuth_Authentication ($url){
$_SESSION['access_token'] = false;
header("Location: $url");
}
function CreateForm(){
$data = getURL('https://api.citrixonline.com/G2M/rest/meetings?oauth_token='.$_SESSION['access_token'],false);
}
function OAuth_Exchanging_Response_Key($code,$url){
if($_SESSION['access_token']){
CreateForm();
return true;
}
$data = getURL(str_replace('{responseKey}',$code,$url));
if(IsJsonString($data)){
$data = json_decode($data);
$_SESSION['access_token'] = $data->access_token;
CreateForm();
}else{
echo 'error';
}
}
/*
* Helper functions
*/
/*
* checks if a string is json
*/
function IsJsonString($str){
try{
$jObject = json_decode($str);
}catch(Exception $e){
return false;
}
return (is_object($jObject)) ? true : false;
}
/*
* CURL function to get url
*/
function getURL($url,$auth_token = false,$data=false){
// Initialize session and set URL.
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
// Set so curl_exec returns the result instead of outputting it.
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
if($auth_token){
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Authorization: OAuth oauth_token='.$auth_token));
}
if($data){
curl_setopt($ch, CURLOPT_POST,true);
$d = json_encode('{ "subject":"test", "starttime":"2011-12-01T09:00:00Z", "endtime":"2011-12-01T10:00:00Z", "passwordrequired":false, "conferencecallinfo":"test", "timezonekey":"", "meetingtype":"Scheduled" }');
echo implode('&', array_map('urlify',array_keys($data),$data));
echo ';';
curl_setopt($ch, CURLOPT_POSTFIELDS,
implode('&', array_map('urlify',array_keys($data),$data))
);
}
// Get the response and close the channel.
$response = curl_exec($ch);
/*
* if redirect, redirect
*/
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($code == 301 || $code == 302) {
preg_match('/<a href="(.*?)">/', $response, $matches);
$newurl = str_replace('&','&',trim(array_pop($matches)));
$response = getURL($newurl);
} else {
$code = 0;
}
curl_close($ch);
return $response;
}
function urlify($key, $val) {
return urlencode($key).'='.urlencode($val);
}
to start the connect process you need to make a request to the php file fith send=1. I tryed diffrent atempts to get the list of meetings but could not get a good response.
Did anybody had prev problems with this or know of a solution for this?
Edit:
This is not a curl error, the server responds with error messages, in the forums from citrix they say it should work, no further details on why it dosen't work, if I have a problem with the way I implemented the oauth or the request code. The most comon error I get is: "error code:31305" that is not documented on the forum.
[I also posted this on the Citrix Developer Forums, but for completeness will mention it here as well.]
We are still finalizing the documentation for these interfaces and some parameters which are written as optional are actually required.
Compared to your example above, changes needed are:
set timezonekey to 67 (Pacific time)
set passwordrequired to false
set conferencecallinfo to Hybrid (meaning: both PSTN and VOIP will be provided)
Taking those changes into account, your sample data would look more like the following:
{"subject":"test meeting", "starttime":"2012-02-01T08:00:00",
"endtime":"2012-02-01T09:00:00", "timezonekey":"67",
"meetingtype":"Scheduled", "passwordrequired":"false",
"conferencecallinfo":"Hybrid"}
You can also check out a working PHP sample app I created: http://pastebin.com/zE77qzAz

Categories