Skip to content

Commit

Permalink
First Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Alejandro Labrada Diaz committed Apr 2, 2015
0 parents commit bf3e43c
Show file tree
Hide file tree
Showing 8 changed files with 304 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
### Composer template
composer.phar
vendor/
composer.lock
.idea

# Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file
# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
# composer.lock
22 changes: 22 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
The MIT License (MIT)

Copyright (c) 2015 Alejandro Labrada Diaz

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Soap Client using Curl [![version][packagist-version]][packagist-url]

[![Downloads][packagist-downloads]][packagist-url]
[![Dependencies][versioneye-image]][versioneye-url]
[![License][packagist-license]][license-url]
27 changes: 27 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "aleplusplus/soapclient-curl-php",
"description": "Soap Client using Curl",
"keywords": ["soap", "curl", "non-wsdl", "client", "sri"],
"type": "library",
"require": {
"php": ">=5.4.0",
"ext-curl": "*",
"ext-json": "*"
},
"license": "MIT",
"authors": [
{
"name": "Alejandro Labrada Diaz",
"email": "[email protected]"
}
],
"minimum-stability": "dev",
"autoload": {
"psr-0": {
"SoapClientCurl": "src"
}
},
"support": {
"email": "[email protected]"
}
}
4 changes: 4 additions & 0 deletions src/SoapClientCurl.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?php

require_once dirname(__FILE__) . '/SoapClientCurl/SoapClientRequest.php';
require_once dirname(__FILE__) . '/SoapClientCurl/SoapClientResponse.php';
149 changes: 149 additions & 0 deletions src/SoapClientCurl/SoapClientRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
<?php

namespace SoapClientCurl;

class SoapClientRequest {

private static $handle = null;
private static $socketTimeout = null;
private static $defaultHeaders = array();

private static $auth = array (
'user' => '',
'pass' => '',
'method' => CURLAUTH_BASIC
);
private static $proxy = array(
'port' => false,
'tunnel' => false,
'address' => false,
'type' => CURLPROXY_HTTP,
'auth' => array (
'user' => '',
'pass' => '',
'method' => CURLAUTH_BASIC
)
);

/**
* Send a cURL request
* @param string $url URL to send the request to
* @param mixed $body request body
* @param array $headers additional headers to send
* @param string $username Authentication username (deprecated)
* @param string $password Authentication password (deprecated)
* @return SoapClientResponse
* @throws \Exception if a cURL error occurs
*/
public static function send($url, $headers = array(), $body = null, $username = null, $password = null)
{
self::$handle = curl_init();

curl_setopt_array(self::$handle, array(
CURLOPT_URL => self::encodeUrl($url),
CURLOPT_POSTFIELDS => $body,
CURLOPT_HTTPHEADER => self::getFormattedHeaders($headers),
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 10,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_POST => true,
CURLOPT_VERBOSE => true,
CURLOPT_HEADER => true
));
if (self::$socketTimeout !== null) {
curl_setopt(self::$handle, CURLOPT_TIMEOUT, self::$socketTimeout);
}
// supporting deprecated http auth method
if (!empty($username)) {
curl_setopt_array(self::$handle, array(
CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
CURLOPT_USERPWD => $username . ':' . $password
));
}
if (!empty(self::$auth['user'])) {
curl_setopt_array(self::$handle, array(
CURLOPT_HTTPAUTH => self::$auth['method'],
CURLOPT_USERPWD => self::$auth['user'] . ':' . self::$auth['pass']
));
}
if (self::$proxy['address'] !== false) {
curl_setopt_array(self::$handle, array(
CURLOPT_PROXYTYPE => self::$proxy['type'],
CURLOPT_PROXY => self::$proxy['address'],
CURLOPT_PROXYPORT => self::$proxy['port'],
CURLOPT_HTTPPROXYTUNNEL => self::$proxy['tunnel'],
CURLOPT_PROXYAUTH => self::$proxy['auth']['method'],
CURLOPT_PROXYUSERPWD => self::$proxy['auth']['user'] . ':' . self::$proxy['auth']['pass']
));
}
$response = curl_exec(self::$handle);
$error = curl_error(self::$handle);
$info = self::getInfo();
if ($error) {
throw new \Exception($error);
}
// Split the full response in its headers and body
$header_size = $info['header_size'];
$header = substr($response, 0, $header_size);
$body = substr($response, $header_size);

return new SoapClientResponse($info, $header, $body);
}

public static function getInfo()
{
return curl_getinfo(self::$handle);
}
public static function getCurlHandle()
{
return self::$handle;
}
public static function getFormattedHeaders($headers)
{
$formattedHeaders = array();
$combinedHeaders = array_change_key_case(array_merge((array) $headers, self::$defaultHeaders));
foreach ($combinedHeaders as $key => $val) {
$formattedHeaders[] = $val;
}
if (!array_key_exists('user-agent', $combinedHeaders)) {
$formattedHeaders[] = 'user-agent: soapclient-request/1.0';
}
if (!array_key_exists('expect', $combinedHeaders)) {
$formattedHeaders[] = 'expect:';
}
return $formattedHeaders;
}
private static function getArrayFromQuerystring($query)
{
$query = preg_replace_callback('/(?:^|(?<=&))[^=[]+/', function ($match) {
return bin2hex(urldecode($match[0]));
}, $query);
parse_str($query, $values);
return array_combine(array_map('hex2bin', array_keys($values)), $values);
}

/**
* Ensure that a URL is encoded and safe to use with cURL
* @param string $url URL to encode
* @return string
*/
private static function encodeUrl($url)
{
$url_parsed = parse_url($url);
$scheme = $url_parsed['scheme'] . '://';
$host = $url_parsed['host'];
$port = (isset($url_parsed['port']) ? $url_parsed['port'] : null);
$path = (isset($url_parsed['path']) ? $url_parsed['path'] : null);
$query = (isset($url_parsed['query']) ? $url_parsed['query'] : null);
if ($query !== null) {
$query = '?' . http_build_query(self::getArrayFromQuerystring($query));
}
if ($port && $port[0] !== ':') {
$port = ':' . $port;
}
$result = $scheme . $host . $port . $path . $query;
return $result;
}
}
59 changes: 59 additions & 0 deletions src/SoapClientCurl/SoapClientResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

namespace SoapClientCurl;

class SoapClientResponse
{
public $info;
public $headers;
public $body;

/**
* @param array $info response curl_getinfo in Curl request
* @param string $headers raw header string from cURL response
* @param string $raw_body the raw body of the cURL response
* @internal param array $json_args arguments to pass to json_decode function
*/
public function __construct($info, $headers, $raw_body)
{
$this->info = $info;
$this->headers = $this->parseHeaders($headers);
$this->body = $raw_body;
}

/**
* if PECL_HTTP is not available use a fall back function
*
* thanks to [email protected]
* http://php.net/manual/en/function.http-parse-headers.php#112986
*/
private function parseHeaders($raw_headers)
{
if (function_exists('http_parse_headers')) {
return http_parse_headers($raw_headers);
} else {
$key = '';
$headers = array();
foreach (explode("\n", $raw_headers) as $i => $h) {
$h = explode(':', $h, 2);
if (isset($h[1])) {
if (!isset($headers[$h[0]])) {
$headers[$h[0]] = trim($h[1]);
} elseif (is_array($headers[$h[0]])) {
$headers[$h[0]] = array_merge($headers[$h[0]], array(trim($h[1])));
} else {
$headers[$h[0]] = array_merge(array($headers[$h[0]]), array(trim($h[1])));
}
$key = $h[0];
} else {
if (substr($h[0], 0, 1) == "\t") {
$headers[$key] .= "\r\n\t" . trim($h[0]);
} elseif (!$key) {
$headers[0] = trim($h[0]);
}
}
}
return $headers;
}
}
}
29 changes: 29 additions & 0 deletions tests/SoapClientRequestTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

require_once __DIR__ . '/../vendor/autoload.php'; // Autoload files using Composer autoload

use SoapClientCurl\SoapClientRequest;

// Clave de Acceso para una factura de Esdinamico en Pruebas
$claveAccesoComprobante = '1302201501179188978900110010010000100520001005215';

// Ambiente de prueba de SRI
$url = 'https://celcer.sri.gob.ec/comprobantes-electronicos-ws/AutorizacionComprobantes';

// Cuerpo del SOAP para la consulta
$body = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ec="http://ec.gob.sri.ws.autorizacion">
<soapenv:Header/>
<soapenv:Body>
<ec:autorizacionComprobante>
<!--Optional:-->
<claveAccesoComprobante>'.$claveAccesoComprobante.'</claveAccesoComprobante>
</ec:autorizacionComprobante>
</soapenv:Body>
</soapenv:Envelope>';

// Cabacera de la peticion
$headers = array('Content-Type: text/xml; charset=utf-8', 'Content-Length: '.strlen($body));

$result = SoapClientRequest::send($url,$headers, $body);

var_dump($result);

0 comments on commit bf3e43c

Please sign in to comment.