Hashes not similar between PHP and Paw REST Client - php

I'm building a HMAC API and I have issues testing the hashing with Paw.
On Paw I have this payload:
GET:/hello/world:"":9a6e30f2016370b6f2dcfb6880501d7f2305d69bout
and a custom HMAC-SHA256 variable (actually function like this that sets it in the X-Hash header.
X-Hash: 4Cq2yehWumDcUk1dYyfhm6qWjJVBkOCB8o12f5l0WGE=
In my PHP API I have the same thing:
GET:/hello/world:"":9a6e30f2016370b6f2dcfb6880501d7f2305d69bout
and used:
hash_hmac('sha256', $this->getPayload(), '9a6e30f2016370b6f2dcfb6880501d7f2305d69bout', false);
So when comparing the hashes:
Paw: 4Cq2yehWumDcUk1dYyfhm6qWjJVBkOCB8o12f5l0WGE=
PHP: 6961b9d1f6e986c49d963cbebd691fa68dfa59b4ce3b7f05320c2d43eae3c7c3
They are very different. Any idea why is that?
Update
Paw Code:
function evaluate(context){
var loc = getLocation(context.getCurrentRequest().url);
var payload = "";
payload += context.getCurrentRequest().method + ':';
payload += loc.pathname + ':';
payload += JSON.stringify(context.getCurrentRequest().body) + ':';
payload += "9a6e30f2016370b6f2dcfb6880501d7f2305d69bout"; // Private key
return payload;
};
function getLocation(href) {
var match = href.match(/^(https?\:)\/\/(([^:\/?#]*)(?:\:([0-9]+))?)(\/[^?#]*)(\?[^#]*|)(#.*|)$/);
return match && {
protocol: match[1],
host: match[2],
hostname: match[3],
port: match[4],
pathname: match[5],
search: match[6],
hash: match[7]
}
}
PHP Code (with lots of comments):
if (strpos(strtoupper($authHeader), 'HMAC') !== 0) {
echo 'out';
throw new HttpForbiddenException();
}
else {
$hmacSignature = $app->request->headers()->get('X-Hash');
$publicKey = $app->request->headers()->get('X-Public');
if ( empty($hmacSignature) || empty($publicKey) ) {
echo 'out2';
throw new HttpForbiddenException();
}
else {
$this->hmacManager->setPublicKey($publicKey);
print '$publickey = ' . $publicKey . '<br>';
// Validate if base64_encoded or not
if( base64_decode($hmacSignature, true) !== FALSE ) {
$binaryString = base64_decode($hmacSignature);
$hmacSignature = bin2hex($binaryString);
print 'decoding ' . '<br>';
}
$this->hmacManager->setHmacSignature($hmacSignature);
print '$hmacSignature = ' . $hmacSignature . '<br>';
$this->hmacManager->setRequestMethod($app->request->getMethod());
print 'method = ' . $app->request->getMethod() . '<br>';
$this->hmacManager->setRequestResourceUri($app->request->getResourceUri());
print 'uri = ' . $app->request->getResourceUri() . '<br>';
$requestBody = $app->request()->getBody();
if (Utils::isJson($requestBody)) {
$requestBody = json_decode($requestBody);
}
$this->hmacManager->setRequestBody(json_encode($requestBody));
print 'body = ' . json_encode($requestBody) . '<br>';
print 'private key = ' . $this->hmacManager->getPrivateKey() . '<br>';
$payload = '';
$payload .= $this->hmacManager->getRequestMethod() . ":";
$payload .= $this->hmacManager->getRequestResourceUri() . ":";
$payload .= $this->hmacManager->getRequestBody() . ":";
$payload .= $this->hmacManager->getPrivateKey();
print 'PHP payload [' . $payload . ']';
$this->hmacManager->setPayload($payload);
$hmacValue = $this->hmacManager->generateHmac();
$isValid = $this->hmacManager->isValid($this->hmacManager->generateHmac(), $hmacSignature);
if ($isValid !== true) {
echo 'out3';
throw new HttpForbiddenException();
}
}
}
generateHmac from another class:
public function generateHmac()
{
print 'Generating HMAC' . '<br>';
$algorithm = $this->getAlgorithm();
print 'algo ' . $algorithm . '<br>';
$privateKey = $this->getPrivateKey();
print 'privk ' . $privateKey . '<br>';
if (empty($algorithm)) {
throw new \RuntimeException('Algorithm must be set and not empty');
} elseif (empty($privateKey)) {
throw new \RuntimeException('Private key must be set and not empty');
}
print 'payload ' . $this->getPayload() . '<br>';
$hash = hash_hmac($this->getAlgorithm(), $this->getPayload(), $this->getPrivateKey(), false);
print 'php hasj: ' . $hash . '<br>';
return $hash;
}
Finally, here's the output statements:
$publickey = 95f97b93560f951b4cae46c86d03d9b1a81d4ae8
decoding
$hmacSignature = e02ab6c9e856ba60dc524d5d6327e19baa968c954190e081f28d767f99745861
method = GET
uri = /hello/world
body = ""
private key = 9a6e30f2016370b6f2dcfb6880501d7f2305d69bout
PHP payload [GET:/hello/world:"":9a6e30f2016370b6f2dcfb6880501d7f2305d69bout]
Generating HMAC
algo sha256
privk 9a6e30f2016370b6f2dcfb6880501d7f2305d69bout
payload GET:/hello/world:"":9a6e30f2016370b6f2dcfb6880501d7f2305d69bout
php hash: 6961b9d1f6e986c49d963cbebd691fa68dfa59b4ce3b7f05320c2d43eae3c7c3
Hope it helps!

The paw hash is base64 encoded while the PHP one is in hexadecimal. So decode the paw hash first:
$binary = base64_decode($pawHash);
$hex = bin2hex($binary);
And then compare this to your own hash.

We've just added new Base 64 to Hex conversion dynamic values, this should solve your problem.
Wrap your HMAC signature dynamic value inside the new Base 64 to Hex one, and you'll get a valid hexadecimal signature:
You can install this new dynamic value here: Base 64 to Hex Dynamic Value

Related

Laravel Undefined Property Error with Google Pagespeed API

I'm a beginner in using laravel. For my webapp I want to use the Google API PageSpeed. When visiting /pagespeed, it gives me this error: ErrorException (E_NOTICE)
Undefined property: stdClass::$ruleScore
Also I'm not sure if i made a correct return. I just want to show the meassured data on the /pagespeed page.
Couldn't really find an answer for my problem, I hope you can help.
I used the pagespeed.php code from https://gist.github.com/typhonius/6259822/revisions and put this in my PagespeedController:
public function pageSpeed(){
$url = 'https://www.facebook.com';
$key = 'my API key';
// View https://developers.google.com/speed/docs/insights/v1/getting_started#before_starting to get a key
$data = json_decode(file_get_contents("https://www.googleapis.com/pagespeedonline/v1/runPagespeed?url=$url&key=$key"));
$dat = $data->formattedResults->ruleResults;
foreach($dat as $d) {
$name = $d->localizedRuleName;
$score = $d->ruleScore;
print "\nTest: " . $name . "\n";
print "Score: " . $score . "\n";
if ($score != 100) {
if (isset($d->urlBlocks[0]->header->args)) {
$advice_header = replace_placeholders($d->urlBlocks[0]->header->format, $d->urlBlocks[0]->header->args);
}
else {
$advice_header = $d->urlBlocks[0]->header->format;
}
print "Advice: " . $advice_header . "\n";
foreach ($d->urlBlocks[0]->urls as $url) {
$advice = replace_placeholders($url->result->format, $url->result->args);
print $advice . "\n";
}
}
};
function replace_placeholders($format, $args) {
$i = 1;
foreach ($args as $arg) {
$format = str_replace("\$" . $i, "$arg->value", $format);
$i++;
}
return view('pagespeed')->with('format');
}
This is in my views folder: pagespeed.blade.php:
#extends('layouts.app')
#section('content')
<h1>Page Speed</h1>
#endsection
This is my Route in web.php:
Route::get('/pagespeed', 'PagespeedController#pageSpeed');
Change this
$score = $d->ruleScore;
to
$score = $d->score;

Intuit Quickbooks Accounting API OAuth with Developer not working at all

I only want to grab information using the Quickbooks API (that seems like this should be possible via their API). I setup an App on their Development site, linked it to the Quickbooks Company I created, and am trying to run this code to get anything from the curl response, but all I am getting are Authorization Failure (401) Messages. Why is it not being authorized? Been studying this site for 12 hours and none of their examples that they provide even work. Am using this page as a reference: https://developer.intuit.com/docs/0050_quickbooks_api/0010_your_first_request/rest_essentials_for_the_quickbooks_api and this: https://developer.intuit.com/docs/0100_accounting/0300_developer_guides/0015_calling_data_services#/The_authorization_header
My index.php file is as follows:
<?php
define('IS_SANDBOX', 1);
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'classes' . DIRECTORY_SEPARATOR . 'oAuth.php');
// GET baseURL/v3/company/companyID/resourceName/entityID
// consumer and consumer_secret
$oAuth = new QuickBooks_IPP_OAuth('qyprdwX21R3klmiskW3AaYLnDRGNLn', 'FDPpxScC6CIgoA07Uc2NYtZJk45CqNDI1Gw4zntn');
$request = array(
'url' => array(
'base_request_uri' => IS_SANDBOX == 1 ? 'https://sandbox-quickbooks.api.intuit.com' : 'https://quickbooks.api.intuit.com',
'version' => 'v3',
'company' => 'company',
'companyID' => '123145768959777'
),
'query' => 'SELECT * FROM ESTIMATE',
'headers' => array(
'Host' => IS_SANDBOX == 1 ? 'sandbox-quickbooks.api.intuit.com' : 'quickbooks.api.intuit.com',
'Accept' => 'application/json',
'User-Agent' => 'APIExplorer'
)
);
$request_url = implode('/', $request['url']) . '/query?query=' . str_replace('+', ' ', str_replace('%7E', '~', rawurlencode($request['query']))) . '&minorversion=4';
// token, and token_secret
$headers = $oAuth->sign('GET', $request_url, 'qyprdaiy37CxGCuB8ow8XK76FYii3rnRU4AIQrHsZDcVFNnV', 'wWcpmPffdPABp6LNNyYgnraTft7bgdygAmTML0aB');
$request['headers']['Authorization'] = 'OAuth ' . array_pop($headers);
$response = curl($request_url, $request['headers']);
echo '<pre>', var_dump($response), '</pre>';
echo '<pre>', var_dump($request['headers']), '</pre>';
function curl($url, $headers) {
try {
$request_headers = array();
$ch = curl_init();
if (FALSE === $ch)
throw new Exception('failed to initialize');
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
if (!empty($headers)) {
foreach($headers as $key => $value)
{
if ($key == 'GET')
{
$request_headers[] = $key . ' ' . $value;
continue;
}
$request_headers[] = $key . ': ' . $value;
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $request_headers);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Disable SSL Verfication, so we can get all info from non-SSL site!
}
$data = curl_exec($ch);
$header = curl_getinfo($ch);
echo '<h2>Curl Get Info</h2>';
echo '<pre>', var_dump($header), '</pre>';
if (FALSE === $data)
throw new Exception(curl_error($ch), curl_errno($ch));
else
return $data;
curl_close($ch);
} catch(Exception $e) {
trigger_error(sprintf(
'Curl failed with error #%d: %s',
$e->getCode(), $e->getMessage()), E_USER_ERROR);
}
}
echo '<pre>', var_dump($request_url), '</pre>';
?>
My oAuth.php file looks like this:
<?php
/**
* QuickBooks PHP DevKit
*
* Copyright (c) 2010 Keith Palmer / ConsoliBYTE, LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* #author Keith Palmer <keith#consolibyte.com>
* #license LICENSE.txt
*
* #package QuickBooks
*/
class QuickBooks_IPP_OAuth
{
private $_secrets;
protected $_oauth_consumer_key;
protected $_oauth_consumer_secret;
protected $_oauth_access_token;
protected $_oauth_access_token_secret;
protected $_version = null;
protected $_signature = null;
protected $_keyfile;
/**
*
*/
const NONCE = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const METHOD_POST = 'POST';
const METHOD_GET = 'GET';
const METHOD_PUT = 'PUT';
const METHOD_DELETE = 'DELETE';
const DEFAULT_VERSION = '1.0';
const DEFAULT_SIGNATURE = 'HMAC-SHA1';
const SIGNATURE_PLAINTEXT = 'PLAINTEXT';
const SIGNATURE_HMAC = 'HMAC-SHA1';
const SIGNATURE_RSA = 'RSA-SHA1';
/**
* Create our OAuth instance
*/
public function __construct($oauth_consumer_key, $oauth_consumer_secret)
{
$this->_oauth_consumer_key = $oauth_consumer_key;
$this->_oauth_consumer_secret = $oauth_consumer_secret;
$this->_version = QuickBooks_IPP_OAuth::DEFAULT_VERSION;
$this->_signature = QuickBooks_IPP_OAuth::DEFAULT_SIGNATURE;
}
/**
* Set the signature method
*
*
*/
public function signature($method, $keyfile = null)
{
$this->_signature = $method;
$this->_keyfile = $keyfile;
}
/**
* Sign an OAuth request and return the signing data (auth string, URL, etc.)
*
*
*/
public function sign($method, $url, $oauth_token = null, $oauth_token_secret = null, $params = array())
{
/*
print('got in: [' . $method . '], ' . $url);
print_r($params);
print('<br /><br /><br />');
*/
if (!is_array($params))
{
$params = array();
}
$params = array_merge($params, array(
'oauth_consumer_key' => $this->_oauth_consumer_key,
'oauth_signature_method' => $this->_signature,
'oauth_nonce' => $this->_nonce(),
'oauth_timestamp' => $this->_timestamp(),
'oauth_version' => $this->_version,
));
// Add in the tokens if they were passed in
if ($oauth_token)
{
$params['oauth_token'] = $oauth_token;
}
if ($oauth_token_secret)
{
$params['oauth_secret'] = $oauth_token_secret;
}
// Generate the signature
$signature_and_basestring = $this->_generateSignature($this->_signature, $method, $url, $params);
$params['oauth_signature'] = $signature_and_basestring[1];
/*
print('<pre>');
print('BASE STRING IS [' . $signature_and_basestring[0] . ']' . "\n\n");
print('SIGNATURE IS: [' . $params['oauth_signature'] . ']');
print('</pre>');
*/
$normalized = $this->_normalize($params);
/*
print('NORMALIZE 1 [' . $normalized . ']' . "\n");
print('NORMZLIZE 2 [' . $this->_normalize2($params) . ']' . "\n");
*/
if (false !== ($pos = strpos($url, '?')))
{
$url = substr($url, 0, $pos);
}
$normalized_url = $url . '?' . $normalized; // normalized URL
return array (
0 => $signature_and_basestring[0], // signature basestring
1 => $signature_and_basestring[1], // signature
2 => $normalized_url,
3 => $this->_generateHeader($params, $normalized), // header string
);
}
protected function _generateHeader($params, $normalized)
{
// oauth_signature="' . $this->_escape($params['oauth_signature']) . '",
$str = '';
if (isset($params['oauth_token']))
$str .= rawurlencode('oauth_token') . '="' . rawurlencode($params['oauth_token']) . '", ';
$nonce = rawurlencode(md5(mt_rand()));
$nonce_chars = str_split($nonce);
$formatted_nonce = '';
foreach($nonce_chars as $n => $chr)
{
if (in_array($n, array(8, 12, 16, 20)))
$formatted_nonce .= '-';
$formatted_nonce .= $chr;
}
$str .= rawurlencode('oauth_nonce') . '="' . $formatted_nonce . '", ' .
rawurlencode('oauth_consumer_key') . '="' . rawurlencode($params['oauth_consumer_key']) . '", ' .
rawurlencode(oauth_signature_method) . '="' . rawurlencode($params['oauth_signature_method']) . '", ' .
rawurlencode(oauth_timestamp) . '="' . rawurlencode($params['oauth_timestamp']) . '", ' .
rawurlencode(oauth_version) . '="' . rawurlencode($params['oauth_version']) . '", ' .
rawurlencode(oauth_signature) . '="' . $this->_escape($params['oauth_signature']) . '"';
return str_replace(array(' ', ' ', ' '), '', str_replace(array("\r", "\n", "\t"), ' ', $str));
}
/**
*
*
*/
protected function _escape($str)
{
if ($str === false)
{
return $str;
}
else
{
return str_replace('+', ' ', str_replace('%7E', '~', rawurlencode($str)));
}
}
protected function _timestamp()
{
//return 1326976195;
//return 1318622958;
return time();
}
protected function _nonce($len = 5)
{
//return '1234';
$tmp = str_split(QuickBooks_IPP_OAuth::NONCE);
shuffle($tmp);
//return 'kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg';
return substr(implode('', $tmp), 0, $len);
}
protected function _normalize($params)
{
$normalized = array();
ksort($params);
foreach ($params as $key => $value)
{
// all names and values are already urlencoded, exclude the oauth signature
if ($key != 'oauth_secret')
{
if (is_array($value))
{
$sort = $value;
sort($sort);
foreach ($sort as $subkey => $subvalue)
{
$normalized[] = $this->_escape($key) . '=' . $this->_escape($subvalue);
}
}
else
{
$normalized[] = $this->_escape($key) . '=' . $this->_escape($value);
}
}
}
return implode('&', $normalized);
}
protected function _generateSignature($signature, $method, $url, $params = array())
{
/*
print('<pre>params for signing');
print_r($params);
print('</pre>');
*/
//if (false !== strpos($url, 'get_access'))
/*if (true)
{
print($url . '<br />' . "\r\n\r\n");
die('NORMALIZE MINE [' . $this->_normalize($params) . ']');
}*/
/*
print('<pre>');
print('NORMALIZING [' . "\n");
print($this->_normalize($params) . "]\n\n\n");
print('SECRET KEY FOR SIGNING [' . $secret . ']' . "\n");
print('</pre>');
*/
if (false !== ($pos = strpos($url, '?')))
{
$tmp = array();
parse_str(substr($url, $pos + 1), $tmp);
// Bad hack for magic quotes... *sigh* stupid PHP
if (get_magic_quotes_gpc())
{
foreach ($tmp as $key => $value)
{
if (!is_array($value))
{
$tmp[$key] = stripslashes($value);
}
}
}
$params = array_merge($tmp, $params);
$url = substr($url, 0, $pos);
}
//print('url [' . $url . ']' . "\n");
//print_r($params);
$sbs = $this->_escape($method) . '&' . $this->_escape($url) . '&' . $this->_escape($this->_normalize($params));
//print('sbs [' . $sbs . ']' . "\n");
// Which signature method?
switch ($signature)
{
case QuickBooks_IPP_OAuth::SIGNATURE_HMAC:
return $this->_generateSignature_HMAC($sbs, $method, $url, $params);
case QuickBooks_IPP_OAuth::SIGNATURE_RSA:
return $this->_generateSignature_RSA($sbs, $method, $url, $params);
}
return false;
}
/*
// Pull the private key ID from the certificate
$privatekeyid = openssl_get_privatekey($cert);
// Sign using the key
$sig = false;
$ok = openssl_sign($base_string, $sig, $privatekeyid);
// Release the key resource
openssl_free_key($privatekeyid);
base64_encode($sig)
*/
protected function _generateSignature_RSA($sbs, $method, $url, $params = array())
{
// $res = ...
$res = openssl_pkey_get_private('file://' . $this->_keyfile);
/*
print('key id is: [');
print_r($res);
print(']');
print("\n\n\n");
*/
$signature = null;
$retr = openssl_sign($sbs, $signature, $res);
openssl_free_key($res);
return array(
0 => $sbs,
1 => base64_encode($signature),
);
}
/*
$key = $request->urlencode($consumer_secret).'&'.$request->urlencode($token_secret);
$signature = base64_encode(hash_hmac("sha1", $base_string, $key, true));
*/
protected function _generateSignature_HMAC($sbs, $method, $url, $params = array())
{
$secret = $this->_escape($this->_oauth_consumer_secret);
$secret .= '&';
if (!empty($params['oauth_secret']))
{
$secret .= $this->_escape($params['oauth_secret']);
}
//print('generating signature from [' . $secret . ']' . "\n\n");
return array(
0 => $sbs,
1 => base64_encode(hash_hmac('sha1', $sbs, $secret, true)),
);
}
}
?>
$request['headers'] looks like this:
array(4) {
["Host"]=>
string(33) "sandbox-quickbooks.api.intuit.com"
["Accept"]=>
string(16) "application/json"
["User-Agent"]=>
string(11) "APIExplorer"
["Authorization"]=>
string(306) "OAuth oauth_token="qyprdaiy37CxGCuB8ow8XK76FYii3rnRU4AIQrHsZDcVFNnV",oauth_nonce="189f7f21-6dd9-c136-e208-0f33141feea5",oauth_consumer_key="qyprdwX21R3klmiskW3AaYLnDRGNLn",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1462545676",oauth_version="1.0",oauth_signature="BIpYveqCxlfVT4Ps4qJypS%2BXHh8%3D""
}
The response looks like this:
message=ApplicationAuthenticationFailed; errorCode=003200; statusCode=401
SignatureBaseString: GET&https%3A%2F%2Fsandbox-quickbooks.api.intuit.com%2Fv3%2Fcompany%2F123145768959777%2Fquery&minorversion%3D4%26oauth_consumer_key%3DqyprdwX21R3klmiskW3AaYLnDRGNLn%26oauth_nonce%3D189f7f21-6dd9-c136-e208-0f33141feea5%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1462545676%26oauth_token%3Dqyprdaiy37CxGCuB8ow8XK76FYii3rnRU4AIQrHsZDcVFNnV%26oauth_version%3D1.0%26query%3DSELECT%2520%252A%2520FROM%2520ESTIMATE
The $request_url looks like this:
https://sandbox-quickbooks.api.intuit.com/v3/company/123145768959777/query?query=SELECT%20%2A%20FROM%20ESTIMATE&minorversion=4
Am I forgetting to do something here? Or perhaps something is not correct somehow? I should be getting All Estimates from within the Quickbook Company with ID of 123145768959777, but all I'm getting is 401 Authorization Failure messages.
Am I forgetting to do something here? Or perhaps something is not correct somehow?
Yes, definitely. See below for specifics:
$headers = $oAuth->sign(null, ...
null is not a valid HTTP request method. Valid HTTP request methods are things like GET, POST, etc. Please refer to the HTTP spec and the OAuth spec.
$headers = $oAuth->sign(null, $_SERVER['REQUEST_URI'],
Why are you signing the server request URI? You should be signing the URL that you are sending your curl request to and not the URL the user is visiting on your own website.
$headers = $oAuth->sign(null, $_SERVER['REQUEST_URI'], 'qyprdaiy37CxGCuB8ow8XK76FYii3rnRU4AIQrHsZDcVFNnV', 'wWcpmPffdPABp6LNNyYgnraTft7bgdygAmTML0aB');
You can not hard-code the OAuth access token and secret. They change every 6 months, and thus have to be stored in a database/file somewhere so that you can change them without editing your code every 6 months.
$request_url = implode('/', $request['url']) . '/query?query=' . str_replace('+', ' ', str_replace('%7E', '~', rawurlencode($request['query']))) . '&minorversion=4';
This is the URL you should be signing.
I should be getting All Estimates from within the Quickbook Company with ID of 123145768959777, but all I'm getting is 401 Authorization Failure messages.
If you need further help, it would make a lot of sense to post your actual HTTP requests and responses. There's not a lot anyone will be able to tell you without really seeing the requests being sent, and the responses being received.
Also... you realize that all of this hard work has already been done for you, using the library you've grabbed code from, right? e.g. You don't need to do any of what you're doing - it's just re-inventing the wheel. Just do:
require_once dirname(__FILE__) . '/config.php';
$EstimateService = new QuickBooks_IPP_Service_Estimate();
$estimates = $EstimateService->query($Context, $realm, "SELECT * FROM Estimate STARTPOSITION 1 MAXRESULTS 10");
foreach ($estimates as $Estimate)
{
print('Estimate # ' . $Estimate->getDocNumber() . "\n");
}
Helpful links:
https://github.com/consolibyte/quickbooks-php
https://github.com/consolibyte/quickbooks-php/blob/master/docs/partner_platform/example_app_ipp_v3/
https://github.com/consolibyte/quickbooks-php/blob/master/docs/partner_platform/example_app_ipp_v3/example_invoice_query.php

Amazon MWS API returning SignatureDoesNotMatch

I need to call the Amazon MWS action 'RequestReport' and specify the ReportType as '_GET_FLAT_FILE_OPEN_LISTINGS_DATA_'. i have successfully connected to get the FulfillmentInventory/ListInventorySupply, so i know that the cURL and amazon settings are correct, but every time i submit i get 'The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.' back from the server. i have tried both sort and ksort on line 23 and 14 - in the call to the FulfillmentInventory/ListInventorySupply i had to set it up with two ksorts in order to keep the list of SKUs in the correct order for the API
Here is the code, as i say, the secret, merchant, and keyid are correct:
header('Content-type: application/xml');
$secret = 'secretcodehere';
$param = array();
$param['AWSAccessKeyId'] = 'accessidhere';
$param['Action'] = 'RequestReport';
$param['Merchant'] = 'merchantidhere';
$param['SignatureVersion'] = '2';
$param['Timestamp'] = gmdate("Y-m-d\TH:i:s.\\0\\0\\0\\Z", time());
$param['Version'] = '2009-01-01';
$param['SignatureMethod'] = 'HmacSHA256';
$param['ReportType'] = '_GET_FLAT_FILE_OPEN_LISTINGS_DATA_';
ksort($param);
$url = array();
foreach ($param as $key => $val) {
$key = str_replace("%7E", "~", rawurlencode($key));
$val = str_replace("%7E", "~", rawurlencode($val));
$url[] = "{$key}={$val}";
}
sort($url);
$arr = implode('&', $url);
$sign = 'POST' . "\n";
$sign .= 'mws.amazonservices.com';
$sign .= '/doc/2009-01-01' . "\n";
$sign .= $arr;
$signature = hash_hmac("sha256", $sign, $secret, true);
$signature = urlencode(base64_encode($signature));
$link = "https://mws.amazonservices.com/doc/2009-01-01/?";
$link .= $arr . "&Signature=" . $signature;
/*
echo($link);//for debugging
exit(); */
$ch = curl_init($link);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: text/xml'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
$response = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
print_r($response);
i have tried it in MWS scratchpad and the info is correct and generates the 200 response, and when i check the url against the one generated by the scratchpad it 'looks' correct, so i must be missing something and i hope it is obvious to someone out there, 'cause i am baffled.
btw-scratchpad lists it as SellerId, but the url shows it as Merchant - i have tried both with no joy
Not to throw a curve ball at you, but the only success I've had in using the RequestReport has been through using the PHP library that Amazon created. If you don't have it already here's the link.
This is the code that I just confirmed works to request the report:
<?php
define('AWS_ACCESS_KEY_ID', $am_aws_access_key);
define('AWS_SECRET_ACCESS_KEY', $am_secret_key);
define('MERCHANT_ID', $am_merchant_id);
define('MARKETPLACE_ID', $am_marketplace_id);
include_once ('/link/to/Amazon/library/MarketplaceWebService/Samples/.config.inc.php');
include_once ('functions.php');
$serviceUrl = "https://mws.amazonservices.com";
$config = array (
'ServiceURL' => $serviceUrl,
'ProxyHost' => null,
'ProxyPort' => -1,
'MaxErrorRetry' => 3,
);
$service = new MarketplaceWebService_Client(
AWS_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY,
$config,
APPLICATION_NAME,
APPLICATION_VERSION);
echo '<br />';
$parameters = array (
'Marketplace' => MARKETPLACE_ID,
'Merchant' => MERCHANT_ID,
'ReportType' => '_GET_FLAT_FILE_OPEN_LISTINGS_DATA_',
);
echo '<br /><br/>Request Report Request:<br><br>';
$request = new MarketplaceWebService_Model_RequestReportRequest($parameters);
print_r($request);
invokeRequestReport($service, $request);
echo '<br /><br/>';
And the functions.php file (basically is the important function in the last half of the code in the MarketplaceWebService\Samples\RequestReportSample.php file:
function invokeRequestReport(MarketplaceWebService_Interface $service, $request)
{
try {
$response = $service->requestReport($request);
echo ("Service Response\n");
echo ("=============================================================================\n");
echo(" RequestReportResponse\n");
if ($response->isSetRequestReportResult()) {
echo(" RequestReportResult\n");
$requestReportResult = $response->getRequestReportResult();
if ($requestReportResult->isSetReportRequestInfo()) {
$reportRequestInfo = $requestReportResult->getReportRequestInfo();
echo(" ReportRequestInfo\n");
if ($reportRequestInfo->isSetReportRequestId())
{
echo(" ReportRequestId\n");
echo(" " . $reportRequestInfo->getReportRequestId() . "\n");
}
$report_request_id = $reportRequestInfo->getReportRequestId();
$report_type = '';
if ($reportRequestInfo->isSetReportType())
{
echo(" ReportType\n");
echo(" " . $reportRequestInfo->getReportType() . "\n");
$report_type = $reportRequestInfo->getReportType();
}
if ($reportRequestInfo->isSetStartDate())
{
echo(" StartDate\n");
echo(" " . $reportRequestInfo->getStartDate()->format(DATE_FORMAT) . "\n");
}
if ($reportRequestInfo->isSetEndDate())
{
echo(" EndDate\n");
echo(" " . $reportRequestInfo->getEndDate()->format(DATE_FORMAT) . "\n");
}
if ($reportRequestInfo->isSetSubmittedDate())
{
echo(" SubmittedDate\n");
echo(" " . $reportRequestInfo->getSubmittedDate()->format(DATE_FORMAT) . "\n");
}
if ($reportRequestInfo->isSetReportProcessingStatus())
{
echo(" ReportProcessingStatus\n");
echo(" " . $reportRequestInfo->getReportProcessingStatus() . "\n");
}
if($report_type == '_GET_FLAT_FILE_OPEN_LISTINGS_DATA_') {
if(!empty($report_request_id)) {
$parameters = array (
'Marketplace' => MARKETPLACE_ID,
'Merchant' => MERCHANT_ID,
'Report' => #fopen('php://memory', 'rw+'),
'ReportRequestIdList' => $report_request_id,
);
$report = new MarketplaceWebService_Model_GetReportRequestListRequest($parameters);
print_r($report);
}
}
}
}
if ($response->isSetResponseMetadata()) {
echo(" ResponseMetadata\n");
$responseMetadata = $response->getResponseMetadata();
if ($responseMetadata->isSetRequestId())
{
echo(" RequestId\n");
echo(" " . $responseMetadata->getRequestId() . "\n");
}
}
} catch (MarketplaceWebService_Exception $ex) {
echo("Caught Exception: " . $ex->getMessage() . "\n");
echo("Response Status Code: " . $ex->getStatusCode() . "\n");
echo("Error Code: " . $ex->getErrorCode() . "\n");
echo("Error Type: " . $ex->getErrorType() . "\n");
echo("Request ID: " . $ex->getRequestId() . "\n");
echo("XML: " . $ex->getXML() . "\n");
}
}
EDIT
Here's the important parts of the .config.inc.php file:
<?php
define ('DATE_FORMAT', 'Y-m-d\TH:i:s\Z');
date_default_timezone_set('America/Denver');
$app_name = "Just make up a name like 'Awesome Sync'";
$app_version = "1.0";
define('APPLICATION_NAME', $app_name);
define('APPLICATION_VERSION', $app_version);
set_include_path('/link/to/Amazon/library/');
...rest of code...
EDIT
This code will create the request for the report, however, it doesn't actually create the report. You have to continue to poll Amazon using this same code until you receive a "Complete" or something similar (can't remember the exact word Amazon send back when the report has been created). Then you need to actually retrieve the report.

Push message not received in device

I am struggling for long with push messaging in BlackBerry. I am able to register successfully for push messaging with a returned code of rc=200. However, when I run the server side code, be it in PHP or .Net, I get a successful returned code but the device never receives the message.
My PHP code is as follows:
<?php
ini_set('display_errors','1');
error_reporting(E_ALL);
// APP ID provided by RIM
$appid = '3385-xxxxxxxxxxx';
// Password provided by RIM
$password = 'xxxxxx';
//Deliver before timestamp
$deliverbefore = gmdate('Y-m-d\TH:i:s\Z', strtotime('+35 minutes'));
//An array of address must be in PIN format or "push_all"
$addresstosendto[] = 'xxxx';
$addresses = '';
foreach ($addresstosendto as $value) {
$addresses .= '<address address-value="' . $value . '"/>';
}
// create a new cURL resource
$err = false;
$ch = curl_init();
$messageid = microtime(true);
$data = '--mPsbVQo0a68eIL3OAxnm'. "\r\n" .
'Content-Type: application/xml; charset=UTF-8' . "\r\n\r\n" .
'<?xml version="1.0"?>
<!DOCTYPE pap PUBLIC "-//WAPFORUM//DTD PAP 2.1//EN" "http://www.openmobilealliance.org/tech/DTD/pap_2.1.dtd">
<pap>
<push-message push-id="' . $messageid . '" deliver-before-timestamp="' . $deliverbefore . '" source-reference="' . $appid . '">'
. $addresses .
'<quality-of-service delivery-method="confirmed"/>
</push-message>
</pap>' . "\r\n" .
'--mPsbVQo0a68eIL3OAxnm' . "\r\n" .
'Content-Type: text/plain' . "\r\n" .
'Push-Message-ID: ' . $messageid . "\r\n\r\n" .
stripslashes('r') . "\r\n" .
'--mPsbVQo0a68eIL3OAxnm--' . "\n\r";
// set URL and other appropriate options
curl_setopt($ch, CURLOPT_URL, "https://pushapi.eval.blackberry.com/mss/PD_pushRequest");//"https://cp3385.pushapi.eval.blackberry.com/mss/PD_pushRequest"
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_USERAGENT, "Hallgren Networks BB Push Server/1.0");
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, $appid . ':' . $password);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: multipart/related; boundary=mPsbVQo0a68eIL3OAxnm; type=application/xml", "Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2", "Connection: keep-alive"));
// grab URL and pass it to the browser
echo $xmldata = curl_exec($ch);
// close cURL resource, and free up system resources
curl_close($ch);
//Start parsing response into XML data that we can read and output
$p = xml_parser_create();
xml_parse_into_struct($p, $xmldata, $vals);
$errorcode = xml_get_error_code($p);
if ($errorcode > 0) {
echo xml_error_string($errorcode);
$err = true;
}
xml_parser_free($p);
echo 'Our PUSH-ID: ' . $messageid . "<br \>\n";
if (!$err && $vals[1]['tag'] == 'PUSH-RESPONSE') {
echo 'PUSH-ID: ' . $vals[1]['attributes']['PUSH-ID'] . "<br \>\n";
echo 'REPLY-TIME: ' . $vals[1]['attributes']['REPLY-TIME'] . "<br \>\n";
echo 'Response CODE: ' . $vals[2]['attributes']['CODE'] . "<br \>\n";
echo 'Response DESC: ' . $vals[2]['attributes']['DESC'] . "<br \> \n";
} else {
echo '<p>An error has occured</p>' . "\n";
echo 'Error CODE: ' . $vals[1]['attributes']['CODE'] . "<br \>\n";
echo 'Error DESC: ' . $vals[1]['attributes']['DESC'] . "<br \>\n";
}
?>
My .NET code is as follows:
public bool pushToWidget(string pushedMessage, string pushPin)
{
String BESAddress = "https://pushapi.eval.blackberry.com/mss/PD_pushRequest";
String BESWebserverListenPort = "33074";
String widgetNotificationUrl = "https://pushapi.eval.blackberry.com/mss/PD_pushRequest";
String pushUserName = "xxxx#xxx.com";
String pushPassword = "xxx#xxx";
String pushPort = "33074 ";
string Boundary = "Boundary ";
String ID = "3385-xxxxxxxxxxxxxxxxxxxxx";
//String pushPin = "xxxxxxxx";
string DeliverBefore = DateTime.UtcNow.AddMinutes(60).ToString("s",
System.Globalization.CultureInfo.InvariantCulture) + "Z";
Response.Write(DeliverBefore);
bool success = true;
StringBuilder Data = new StringBuilder();
Data.AppendLine("--" + Boundary);
Data.AppendLine("Content-Type: application/xml; charset=utf-8");
Data.AppendLine("");
Data.AppendLine("<?xml version=\"1.0\"?>");
Data.AppendLine("<!DOCTYPE pap PUBLIC \"-//WAPFORUM//DTD PAP 2.1//EN\">");
Data.AppendLine("<pap>");
Data.AppendLine("<push-message push-id=" + (char)34 + ID + (char)34 + " deliver-before-timestamp=" +
(char)34 + DeliverBefore + (char)34 + " source-reference=" + (char)34 + pushUserName + (char)34 + ">");
Data.AppendLine("<address address-value=\"" + pushPin + "\"/>");
Data.AppendLine("<quality-of-service delivery-method=\"unconfirmed\"/>");
Data.AppendLine("</push-message>");
Data.AppendLine("</pap>");
Data.AppendLine("--" + Boundary);
Data.AppendLine("Content-Type: text/plain");
Data.AppendLine("Push-Message-ID: " + ID);
Data.AppendLine("");
Data.AppendLine(pushedMessage);
Data.AppendLine("--" + Boundary + "--");
Data.AppendLine("");
byte[] bytes = Encoding.ASCII.GetBytes(Data.ToString());
Stream requestStream = null;
HttpWebResponse HttpWRes = null;
HttpWebRequest HttpWReq = null;
try
{
//http://<BESName>:<BESPort>/push?
//String DESTINATTION="<299A7C32/EMAIL>&PORT=<PushPort>&REQUESTURI=/"
// Build the URL to define our connection to the BES.
string httpURL = BESAddress + ":" + BESWebserverListenPort
+ "/push?DESTINATION=" + pushPin + "&PORT=" + pushPort
+ "&REQUESTURI=/";
//make the connection
HttpWReq = (HttpWebRequest)WebRequest.Create(httpURL);
HttpWReq.Method = ("POST");
//add the headers nessecary for the push
HttpWReq.ContentType = "text/plain";
HttpWReq.ContentLength = bytes.Length;
// ******* Test this *******
HttpWReq.Headers.Add("X-Rim-Push-Id", pushPin + "~" + DateTime.Now); //"~" +pushedMessage +
HttpWReq.Headers.Add("X-Rim-Push-Reliability", "application-preferred");
HttpWReq.Headers.Add("X-Rim-Push-NotifyURL", (widgetNotificationUrl + pushPin + "~" + pushedMessage
+ "~" + DateTime.Now).Replace(" ", ""));
// *************************
HttpWReq.Credentials = new NetworkCredential(pushUserName, pushPassword);
Console.WriteLine(pushedMessage);
requestStream = HttpWReq.GetRequestStream();
//Write the data from the source
requestStream.Write(bytes, 0, bytes.Length);
requestStream.Close();
//get the response
HttpWRes = (HttpWebResponse)HttpWReq.GetResponse();
String response = HttpWRes.ToString();
//if the MDS received the push parameters correctly it will either respond with okay or accepted
if (HttpWRes.StatusCode == HttpStatusCode.OK || HttpWRes.StatusCode == HttpStatusCode.Accepted)
{
success = true;
}
else
{
success = false;
}
//Close the streams
HttpWRes.Close();
requestStream.Close();
}
catch (System.Exception e)
{
success = false;
}
return success;
}
I am running the following code in my App to listen for incoming message:
public static void process(PushInputStream pis, Connection conn) {
System.out.println("Reading incoming push message ...");
try {
HttpServerConnection httpConn;
if (conn instanceof HttpServerConnection) {
httpConn = (HttpServerConnection) conn;
} else {
throw new IllegalArgumentException("Can not process non-http pushes, expected HttpServerConnection but have "
+ conn.getClass().getName());
}
String msgId = httpConn.getHeaderField(MESSAGE_ID_HEADER);
String msgType = httpConn.getType();
String encoding = httpConn.getEncoding();
System.out.println("Message props: ID=" + msgId + ", Type=" + msgType + ", Encoding=" + encoding);
boolean accept = true;
if (!alreadyReceived(msgId)) {
byte[] binaryData;
if (msgId == null) {
msgId = String.valueOf(System.currentTimeMillis());
}
if (msgType == null) {
System.out.println("Message content type is NULL");
accept = false;
} else if (msgType.indexOf(MESSAGE_TYPE_TEXT) >= 0) {
// a string
int size = pis.read(buffer);
binaryData = new byte[size];
System.arraycopy(buffer, 0, binaryData, 0, size);
PushMessage message = new PushMessage(msgId, System.currentTimeMillis(), binaryData, true, true );
String text = new String( message.getData(), "UTF-8" );
try{
final Dialog screen = new Dialog(Dialog.D_OK_CANCEL, " "+text,
Dialog.OK,
//mImageGreen.getBitmap(),
null, Manager.VERTICAL_SCROLL);
final UiEngine ui = Ui.getUiEngine();
Application.getApplication().invokeAndWait(new Runnable() {
public void run() {
NotificationsManager.triggerImmediateEvent(0x749cb23a76c66e2dL, 0, null, null);
ui.pushGlobalScreen(screen, 0, UiEngine.GLOBAL_QUEUE);
}
});
screen.setDialogClosedListener(new MyDialogClosedListener());
}
catch (Exception e) {
// TODO: handle exception
}
// TODO report message
} else {
System.out.println("Unknown message type " + msgType);
accept = false;
}
} else {
System.out.println("Received duplicate message with ID " + msgId);
}
pis.accept();
} catch (Exception e) {
System.out.println("Failed to process push message: " + e);
}
}
The above is part of the App code that is run to read the incoming message. I have posted the server side codes in detail as I am struggling with Push Messaging for a very long time and would appreciate if somebody can guide me in the right direction. Considering the fact that I am getting a "success" returned code from the server side code, could the issue be in listening and processing the message at the front end? I can share the client side App on request. Please help.
You have to open socket connection in order to listen to incoming push. Here is the runnable class which you can use to open socket connection. Your process function can be called once you receive the incoming push message.
You can call using -
MessageReadingThread messageReadingThread = new MessageReadingThread();
Thread oThread = new Thread(messageReadingThread);
oThread.start();
/**
* Thread that processes incoming connections through
* {#link PushMessageReader}.
*/
private class MessageReadingThread implements Runnable
{
private final BIS_CONNECTION_SUFFIX = ";ConnectionType=mds-public";
private final String CONNECTION_SUFFIX = ";deviceside=false";
/** Flag indicating Listening thread is running or not */
private boolean bRunning;
/** ServerSocketConnection instance to Listen for incoming push message */
private ServerSocketConnection oSocket;
private HttpServerConnection oHttpServerConnection;
private InputStream oInputStream;
private MDSPushInputStream oMDSPushInputStream; // PushInputStream
/**
* {#inheritDoc}
*
* #see java.lang.Thread#run()
*/
public void run()
{
String strUrl = "http://:" + PUSH_PORT + CONNECTION_SUFFIX + BIS_CONNECTION_SUFFIX;
try
{
oSocket = (ServerSocketConnection) Connector.open(strUrl);
m_bIsPortOpen = true;
bRunning = true;
}
catch (IOException ex)
{
// can't open the port, probably taken by another application
fnStopRunning();
}
while (bRunning)
{
try
{
Object object = oSocket.acceptAndOpen();
oHttpServerConnection = (HttpServerConnection) object;
oInputStream = oHttpServerConnection.openInputStream();
oMDSPushInputStream = new MDSPushInputStream(
oHttpServerConnection, oInputStream);
process(oMDSPushInputStream,
oHttpServerConnection, app);
}
catch (Exception e)
{
// Failed to read push message
bRunning = false;
}
finally
{
close(null, oInputStream, null);
close(oHttpServerConnection, oMDSPushInputStream, null);
}
}
}
/**
* Stop running.
*/
private void fnStopRunning()
{
bRunning = false;
m_bIsPortOpen = false;
close(oSocket, null, null);
}
/**
* Safely closes connection and streams.
*/
private void close(Connection oConnection, InputStream oInputStream,
OutputStream oOutputStream)
{
if (oOutputStream != null)
{
try
{
oOutputStream.close();
}
catch (IOException e)
{
}
}
if (oInputStream != null)
{
try
{
oInputStream.close();
}
catch (IOException e)
{
}
}
if (oConnection != null)
{
try
{
oConnection.close();
}
catch (IOException e)
{
}
}
}
}

Executing a PHP script from within nested batch scripts

I'm trying to rewrite our Windows FTP server configuration script that was created for IIS and now we're trying to get something similar working for Filezilla Server.
The structure goes like this, we have a batch file which is a for loop of another batch file, so we can batch configure our FTP websites. This batch file I'm currently trying to get working contains a line of code to execute a PHP script to set up the FTP username and password in Filezilla as well as doing a few other neat things.
Now, running CreateIIStmp.bat var1 var2 works just fine. But executing the BatchCreateIIS.bat seems to skip the execution of the php script, or the php script fails. (I'm just looking into how I put in some error handling into the PHP script to catch any error and display it, but I'm not a (PHP) developer/coder so I'll be updating this when I figure it out.)
Here's a stripped down version of what I'm talking about:
The initial batch file BatchCreateIIS.bat:
#Echo off
for /f %%X in (NewWebsiteEntries.txt) do start cmd.exe /c "CreateIIStmp.bat %%X %%X"
echo ...
echo *** BATCH PROCESS HAS BEEN COMPLETED ***
pause
The CreateIIStmp.bat:
# echo off
C:\php5\php-win.exe -f filezilla-user-script.php -- %1 %2
pause
#echo on
The NewWebsiteEntries.txt:
somedomain.com ftpuname
somedomain2.net ftpuname2
The filezilla-user-script.php:
<?php
$xmlfolder = 'C:/Program Files (x86)/FileZilla Server/';
$xmlfilename = 'FileZilla Server.xml';
$ftpRoot = 'C:/inetpub/wwwroot/';
$ftpDocumentation = 'C:/Documentation ftp server/';
$xmlfile = $xmlfolder . $xmlfilename;
$xmlbackupfile = $xmlfolder . #date("Y-m-d-H-i-s") . '_FileZilla_Server.xml';
// Copy Config for backup
createXMLbackup($xmlfile,$xmlbackupfile);
//Load XML file
$xml = simplexml_load_file($xmlfile);
$msg = "Allowed usernames: 20 characters out of a...z A...Z 0...9 _ \n\nPlease input username (Ctrl+C to quit)";
// Copy Config for backup before each change, too.
createXMLbackup($xmlfile,$xmlbackupfile);
echo "\n\n";
$input = ($argv[2]);
echo "\n";
//echo 'Userinput: ' . $input . "\n";
$isvalid = isUserID($input);
//var_dump($isvalid);
if($isvalid)
{
$ftpUserFolder = $ftpRoot . ($argv[1]);
if ((file_exists($ftpUserFolder) && is_dir($ftpUserFolder)))
{
echo "The directory $ftpUserFolder exists.\nPlease select another user name.\n";
}
else
{
//echo "The directory $ftpUserFolder does not exist\n";
if(!check_user_exists($xml,$input))
{
echo "Adding user $input...\n";
if (!mkdir($ftpUserFolder))
{
die("Could not create directory $ftpUserFolder \n");
}
else
{
echo "Directory $ftpUserFolder created.\n";
}
$password = generatePassword();
//echo 'Password: ' . $password . "\n";
$user = $xml->Users->addChild('User');
$user->addAttribute('Name', $input);
$option = $user->addChild('Option', md5($password));
$option->addAttribute('Name', 'Pass');
$option = $user->addChild('Option');
$option->addAttribute('Name', 'Group');
$option = $user->addChild('Option', '0');
$option->addAttribute('Name', 'Bypass server userlimit');
$option = $user->addChild('Option', '0');
$option->addAttribute('Name', 'User Limit');
$option = $user->addChild('Option', '0');
$option->addAttribute('Name', 'IP Limit');
$option = $user->addChild('Option', '1');
$option->addAttribute('Name', 'Enabled');
$option = $user->addChild('Option', 'none');
$option->addAttribute('Name', 'Comments');
$option = $user->addChild('Option', '0');
$option->addAttribute('Name', 'ForceSsl');
$filter = $user->addChild('IpFilter');
$filter->addChild('Disallowed');
$filter->addChild('Allowed');
$permissions = $user->addChild('Permissions');
$permission = $permissions->addChild('Permission');
$permission->addAttribute('Dir', str_replace("/","\\",$ftpUserFolder));
$option = $permission->addChild('Option', '1');
$option->addAttribute('Name', 'FileRead');
$option = $permission->addChild('Option', '1');
$option->addAttribute('Name', 'FileWrite');
$option = $permission->addChild('Option', '0');
$option->addAttribute('Name', 'FileDelete');
$option = $permission->addChild('Option', '1');
$option->addAttribute('Name', 'FileAppend');
$option = $permission->addChild('Option', '1');
$option->addAttribute('Name', 'DirCreate');
$option = $permission->addChild('Option', '0');
$option->addAttribute('Name', 'DirDelete');
$option = $permission->addChild('Option', '1');
$option->addAttribute('Name', 'DirList');
$option = $permission->addChild('Option', '1');
$option->addAttribute('Name', 'DirSubdirs');
$option = $permission->addChild('Option', '1');
$option->addAttribute('Name', 'IsHome');
$option = $permission->addChild('Option', '0');
$option->addAttribute('Name', 'AutoCreate');
$speed = $user->addChild('SpeedLimits');
$speed->addAttribute('DlType', '1');
$speed->addAttribute('DlLimit', '10');
$speed->addAttribute('ServerDlLimitBypass', '0');
$speed->addAttribute('UlType', '1');
$speed->addAttribute('UlLimit', '10');
$speed->addAttribute('ServerUlLimitBypass', '0');
$speed->addChild('Download');
$speed->addChild('Upload');
$rv = $xml->asXML($xmlfile);
//echo $rv . "\n";
if(!$rv)
{
die('SimpleXML could not write file');
}
//$newentry = $xml->addChild('element', iconv('ISO-8859-1', 'UTF-8', $write));
//The DOM extension uses UTF-8 encoding. Use utf8_encode() and utf8_decode()
//to work with texts in ISO-8859-1 encoding or Iconv for other encodings.
//make human readable, parse using DOM function
//otherwise everything will be printed on one line
if( !file_exists($xmlfile) ) die('Missing file: ' . $xmlfile);
else
{
$dom = new DOMDocument("1.0","ISO-8859-1");
//Setze die Flags direkt nach dem Initialisieren des Objektes:
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
//$dl = #$dom->load($xmlfile); // remove error control operator (#) to print any error message generated while loading.
$dl = $dom->load($xmlfile); // remove error control operator (#) to print any error message generated while loading.
if ( !$dl ) die('Error while parsing the document: ' . $xmlfile);
//echo $dom->save($xmlfile) . "\n";
if(!$dom->save($xmlfile))
{
die('DOMDocument could not write file');
}
}
//Create documentation
$docuFile = $ftpDocumentation . $input . '.txt';
//echo $docuFile . "\n";
$docuString = "Username: " . $input . "\n";
$docuString = $docuString . "Password: " . $password . "\n";
$docuString = $docuString . "Folder: " . str_replace("/","\\",$ftpUserFolder) . "\n";
$docuString = $docuString . "Date: " . #date("d.m.Y") . "\n";
// $docuString = $docuString . "\n";
// $docuString = $docuString . "Direct link:\n";
// $docuString = $docuString . "ftp://" . $input . ":" . $password . "#ftp.yourcompany.com";
$handleDocuFile = fopen($docuFile, "wt");
if(!$handleDocuFile)
{
die('Could not fopen docu file');
}
$rv = fwrite($handleDocuFile, $docuString);
if(!$rv)
{
die('Could not fwrite docu file');
}
// Close xml file
$rv = fclose($handleDocuFile);
if(!$rv)
{
die('Could not fclose docu file');
}
echo "Documentary file written.\n";
$ftpExecutable = "\"C:\\Program Files (x86)\\FileZilla Server\\FileZilla server.exe\" /reload-config";
$command = $ftpExecutable;
$last_line = system($command, $retval);
echo ("Filezilla reloaded, user active.\n");
echo ("Close Notepad to add another user or quit.\n");
$command = "C:\\Windows\\System32\\notepad.exe $docuFile";
$last_line = system($command, $retval);
}
else
{
echo "Username $input already exists...\n";
}
}
}
else
{
echo "Username $input is invalid\n";
}
function check_user_exists($xml,$username)
{
$children=$xml->Users->children();
foreach($children as $child)
{
if ($child->getName()=='User')
{
foreach($child->attributes() as $attributes )
{
if(trim($attributes) == trim($username))
{
echo "Username $username already exists... \n";
return true;
}
}
}
}
return false;
}
function isUserID($username)
{
//return preg_match('/^\w{2,20}$/', $username);
return preg_match('/^[A-Za-z0-9][A-Za-z0-9]*(?:_[A-Za-z0-9]+)*$/', $username);
}
function isValid($str)
{
//return !preg_match('/[^A-Za-z0-9.#\\-$]/', $str);
return !preg_match('/[^A-Za-z0-9\_\-]/', $str);
}
function getInput($msg)
{
fwrite(STDOUT, "$msg: ");
$varin = trim(fgets(STDIN,20));
return $varin;
//$input = fgets($fr,128); // read a maximum of 128 characters
}
function createXMLbackup($xmlfile,$xmlbackupfile)
{
// Copy Config for backup
$rv = copy($xmlfile,$xmlbackupfile);
if(!$rv)
{
die('Problem creating xml backup file');
}
echo "\nBackup file created\n";
}
function generatePassword ($length = 15)
{
// start with a blank password
$password = "";
$possible = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
// we refer to the length of $possible a few times, so let's grab it now
$maxlength = strlen($possible);
// check for length overflow and truncate if necessary
if ($length > $maxlength)
{
$length = $maxlength;
}
// set up a counter for how many characters are in the password so far
$i = 0;
// add random characters to $password until $length is reached
while ($i < $length)
{
// pick a random character from the possible ones
$char = substr($possible, mt_rand(0, $maxlength-1), 1);
// have we already used this character in $password?
if (!strstr($password, $char))
{
// no, so it's OK to add it onto the end of whatever we've already got...
$password .= $char;
// ... and increase the counter by one
$i++;
}
}
// done!
return $password;
}
?>
I've looked around and there are some places that suggest using # in front of calling in PHP so: #C:\php5\php-win.exe -f filezilla-user-script.php -- %1 %2 but that doesn't work, and I can see that my script does work, just not in this nested form.
Maybe there's an approach to this problem that I'm missing? Or something that I don't know about executing scripts in nested batch scripts?
In your BatchCreateIIS.bat, when you use this:
start cmd.exe /c "CreateIIStmp.bat %%X %%X"
the parent cmd.exe will not wait for each instance of CreateIIStmp.bat (and child processes) to finish. Since you seem to be writing to the same XML file, it is likely that the DOM that get written last persists. Instead try this:
call "CreateIIStmp.bat %%X %%X"

Categories