XT Knowledge Base
Hauptseite | Über | Hilfe | FAQ | Spezialseiten | Anmelden

Druckversion | Impressum | Datenschutz | Aktuelle Version

Amzn PHP API

(Unterschied zwischen Versionen)

(Die Seite wurde neu angelegt: „<pre> <? define( 'SHA256_DIGEST_LENGTH', 32 ); class nanoSha2 { // php 4 - 5 compatible class properties var $toUpper; var $platform; …“)
Zeile 1: Zeile 1:
 +
Den nachfolgenden Code habe ich aus verschiedenen Quellen im Internet zusammengetragen, angepasst und integriert.
 +
 +
Das Hauptproblem besteht darin, dass auf den 1&1-Servern PEAR, PECL und das PECL-Module 'crack' nicht installiert ist und es mir nicht gelungen ist, das selbst zu installieren. Das Modul 'crack' erzeugt bei der Installation einen Fehler.
 +
 +
Mit PEAR/Pecl und crack hätte ich einfach das [http://de2.php.net/manual/en/book.hash.php HASH Message Digest Framework] von PHP verwenden und mir einige Stunden Arbeit sparen können.
 +
 +
Deshalb habe ich den von Amazon benötigten HMAC-SHA256-Algorithmus selbst implementiert.
 +
 +
Den SHA256-Algorithmus habe ich von [http://www.nanolink.ca/pub/sha256/sha256.inc.txt hier]
 +
Er stammt von Perry McGee. Das Script kann [http://www.nanolink.ca/pub/sha256 auf dieser Seite] getestet werden.
 +
 +
Der HMAC-Algorithmus stammt von KC Cloyd [http://php.net/manual/en/function.hash-hmac.php]
 +
<pre>
<pre>
&lt;?
&lt;?
Zeile 5: Zeile 18:
class nanoSha2
class nanoSha2
{
{
-
    // php 4 - 5 compatible class properties
 
     var    $toUpper;
     var    $toUpper;
     var    $platform;
     var    $platform;

Version vom 16:24, 12. Aug. 2010

Den nachfolgenden Code habe ich aus verschiedenen Quellen im Internet zusammengetragen, angepasst und integriert.

Das Hauptproblem besteht darin, dass auf den 1&1-Servern PEAR, PECL und das PECL-Module 'crack' nicht installiert ist und es mir nicht gelungen ist, das selbst zu installieren. Das Modul 'crack' erzeugt bei der Installation einen Fehler.

Mit PEAR/Pecl und crack hätte ich einfach das HASH Message Digest Framework von PHP verwenden und mir einige Stunden Arbeit sparen können.

Deshalb habe ich den von Amazon benötigten HMAC-SHA256-Algorithmus selbst implementiert.

Den SHA256-Algorithmus habe ich von hier Er stammt von Perry McGee. Das Script kann auf dieser Seite getestet werden.

Der HMAC-Algorithmus stammt von KC Cloyd [1]

<?
define( 'SHA256_DIGEST_LENGTH', 32 );

class nanoSha2
{
    var     $toUpper;
    var     $platform;

    // Php 4 - 6 compatable constructor
    function __construct( ) 
    {
        // Determine if the caller wants upper case or not.
        $this->toUpper = false;

        // Deteremine if the system is 32 or 64 bit.
        $tmpInt = (int)4294967295;
        $this->platform = ($tmpInt > 0) ? 64 : 32;
    }

    // Do the SHA-256 Padding routine (make input a multiple of 512 bits)
    function char_pad($str)
    {
        $tmpStr = $str;

        $l = strlen($tmpStr)*8;     // # of bits from input string

        $tmpStr .= "\x80";          // append the "1" bit followed by 7 0's

        $k = (512 - (($l + 8 + 64) % 512)) / 8;   // # of 0 bytes to append
        $k += 4;    // PHP Strings will never exceed (2^31)-1, 1st 32bits of
                    // the 64-bit value representing $l can be all 0's

        for ($x = 0; $x < $k; $x++) {
            $tmpStr .= "\0";
        }

        // append the 32-bits representing # of bits from input string ($l)
        $tmpStr .= chr((($l>>24) & 0xFF));
        $tmpStr .= chr((($l>>16) & 0xFF));
        $tmpStr .= chr((($l>>8) & 0xFF));
        $tmpStr .= chr(($l & 0xFF));

        return $tmpStr;
    }

    // Here are the bitwise and functions as defined in FIPS180-2 Standard
    function addmod2n($x, $y, $n = 4294967296)      // Z = (X + Y) mod 2^32
    {
        $mask = 0x80000000;

        if ($x < 0) {
            $x &= 0x7FFFFFFF;
            $x = (float)$x + $mask;
        }

        if ($y < 0) {
            $y &= 0x7FFFFFFF;
            $y = (float)$y + $mask;
        }

        $r = $x + $y;

        if ($r >= $n) {
            while ($r >= $n) {
                $r -= $n;
            }
        }

        return (int)$r;
    }

    // Logical bitwise right shift (PHP default is arithmetic shift)
    function SHR($x, $n)        // x >> n
    {
        if ($n >= 32) {      // impose some limits to keep it 32-bit
            return (int)0;
        }

        if ($n <= 0) {
            return (int)$x;
        }

        $mask = 0x40000000;

        if ($x < 0) {
            $x &= 0x7FFFFFFF;
            $mask = $mask >> ($n-1);
            return ($x >> $n) | $mask;
        }

        return (int)$x >> (int)$n;
    }

    function ROTR($x, $n) { return (int)(($this->SHR($x, $n) | ($x << (32-$n)) & 0xFFFFFFFF)); }
    function Ch($x, $y, $z) { return ($x & $y) ^ ((~$x) & $z); }
    function Maj($x, $y, $z) { return ($x & $y) ^ ($x & $z) ^ ($y & $z); }
    function Sigma0($x) { return (int) ($this->ROTR($x, 2)^$this->ROTR($x, 13)^$this->ROTR($x, 22)); }
    function Sigma1($x) { return (int) ($this->ROTR($x, 6)^$this->ROTR($x, 11)^$this->ROTR($x, 25)); }
    function sigma_0($x) { return (int) ($this->ROTR($x, 7)^$this->ROTR($x, 18)^$this->SHR($x, 3)); }
    function sigma_1($x) { return (int) ($this->ROTR($x, 17)^$this->ROTR($x, 19)^$this->SHR($x, 10)); }

    /*
     * Custom functions to provide PHP support
     */
    // split a byte-string into integer array values
    function int_split($input)
    {
        $l = strlen($input);

        if ($l <= 0) {
            return (int)0;
        }

        if (($l % 4) != 0) { // invalid input
            return false;
        }

        for ($i = 0; $i < $l; $i += 4)
        {
            $int_build  = (ord($input[$i]) << 24);
            $int_build += (ord($input[$i+1]) << 16);
            $int_build += (ord($input[$i+2]) << 8);
            $int_build += (ord($input[$i+3]));

            $result[] = $int_build;
        }

        return $result;
    }

    /**
     * Process and return the hash.
     *
     * @param $str Input string to hash
     * @return string Hexadecimal representation of the message digest
     */
    function sha256( $str )
    {
        unset($binStr);     // binary representation of input string
        unset($hexStr);     // 256-bit message digest in readable hex format

        /*
         * SHA-256 Constants
         *  Sequence of sixty-four constant 32-bit words representing the
         *  first thirty-two bits of the fractional parts of the cube roots
         *  of the first sixtyfour prime numbers.
         */
        $K = array((int)0x428a2f98, (int)0x71374491, (int)0xb5c0fbcf,
                   (int)0xe9b5dba5, (int)0x3956c25b, (int)0x59f111f1,
                   (int)0x923f82a4, (int)0xab1c5ed5, (int)0xd807aa98,
                   (int)0x12835b01, (int)0x243185be, (int)0x550c7dc3,
                   (int)0x72be5d74, (int)0x80deb1fe, (int)0x9bdc06a7,
                   (int)0xc19bf174, (int)0xe49b69c1, (int)0xefbe4786,
                   (int)0x0fc19dc6, (int)0x240ca1cc, (int)0x2de92c6f,
                   (int)0x4a7484aa, (int)0x5cb0a9dc, (int)0x76f988da,
                   (int)0x983e5152, (int)0xa831c66d, (int)0xb00327c8,
                   (int)0xbf597fc7, (int)0xc6e00bf3, (int)0xd5a79147,
                   (int)0x06ca6351, (int)0x14292967, (int)0x27b70a85,
                   (int)0x2e1b2138, (int)0x4d2c6dfc, (int)0x53380d13,
                   (int)0x650a7354, (int)0x766a0abb, (int)0x81c2c92e,
                   (int)0x92722c85, (int)0xa2bfe8a1, (int)0xa81a664b,
                   (int)0xc24b8b70, (int)0xc76c51a3, (int)0xd192e819,
                   (int)0xd6990624, (int)0xf40e3585, (int)0x106aa070,
                   (int)0x19a4c116, (int)0x1e376c08, (int)0x2748774c,
                   (int)0x34b0bcb5, (int)0x391c0cb3, (int)0x4ed8aa4a,
                   (int)0x5b9cca4f, (int)0x682e6ff3, (int)0x748f82ee,
                   (int)0x78a5636f, (int)0x84c87814, (int)0x8cc70208,
                   (int)0x90befffa, (int)0xa4506ceb, (int)0xbef9a3f7,
                   (int)0xc67178f2);

        // Pre-processing: Padding the string
        $binStr = $this->char_pad($str);

        // Parsing the Padded Message (Break into N 512-bit blocks)
        $M = str_split($binStr, 64);

        // Set the initial hash values
        $h[0] = (int)0x6a09e667;
        $h[1] = (int)0xbb67ae85;
        $h[2] = (int)0x3c6ef372;
        $h[3] = (int)0xa54ff53a;
        $h[4] = (int)0x510e527f;
        $h[5] = (int)0x9b05688c;
        $h[6] = (int)0x1f83d9ab;
        $h[7] = (int)0x5be0cd19;

        // loop through message blocks and compute hash. ( For i=1 to N : )
        $N = count($M);
        for ($i = 0; $i < $N; $i++)
        {
            // Break input block into 16 32bit words (message schedule prep)
            $MI = $this->int_split($M[$i]);

            // Initialize working variables
            $_a = (int)$h[0];
            $_b = (int)$h[1];
            $_c = (int)$h[2];
            $_d = (int)$h[3];
            $_e = (int)$h[4];
            $_f = (int)$h[5];
            $_g = (int)$h[6];
            $_h = (int)$h[7];
            unset($_s0);
            unset($_s1);
            unset($_T1);
            unset($_T2);
            $W = array();

            // Compute the hash and update
            for ($t = 0; $t < 16; $t++)
            {
                // Prepare the first 16 message schedule values as we loop
                $W[$t] = $MI[$t];

                // Compute hash
                $_T1 = $this->addmod2n($this->addmod2n($this->addmod2n($this->addmod2n($_h, $this->Sigma1($_e)), $this->Ch($_e, $_f, $_g)), $K[$t]), $W[$t]);
                $_T2 = $this->addmod2n($this->Sigma0($_a), $this->Maj($_a, $_b, $_c));

                // Update working variables
                $_h = $_g; $_g = $_f; $_f = $_e; $_e = $this->addmod2n($_d, $_T1);
                $_d = $_c; $_c = $_b; $_b = $_a; $_a = $this->addmod2n($_T1, $_T2);
            }

            for (; $t < 64; $t++)
            {
                // Continue building the message schedule as we loop
                $_s0 = $W[($t+1)&0x0F];
                $_s0 = $this->sigma_0($_s0);
                $_s1 = $W[($t+14)&0x0F];
                $_s1 = $this->sigma_1($_s1);

                $W[$t&0xF] = $this->addmod2n($this->addmod2n($this->addmod2n($W[$t&0xF], $_s0), $_s1), $W[($t+9)&0x0F]);

                // Compute hash
                $_T1 = $this->addmod2n($this->addmod2n($this->addmod2n($this->addmod2n($_h, $this->Sigma1($_e)), $this->Ch($_e, $_f, $_g)), $K[$t]), $W[$t&0xF]);
                $_T2 = $this->addmod2n($this->Sigma0($_a), $this->Maj($_a, $_b, $_c));

                // Update working variables
                $_h = $_g; $_g = $_f; $_f = $_e; $_e = $this->addmod2n($_d, $_T1);
                $_d = $_c; $_c = $_b; $_b = $_a; $_a = $this->addmod2n($_T1, $_T2);
            }

            $h[0] = $this->addmod2n($h[0], $_a);
            $h[1] = $this->addmod2n($h[1], $_b);
            $h[2] = $this->addmod2n($h[2], $_c);
            $h[3] = $this->addmod2n($h[3], $_d);
            $h[4] = $this->addmod2n($h[4], $_e);
            $h[5] = $this->addmod2n($h[5], $_f);
            $h[6] = $this->addmod2n($h[6], $_g);
            $h[7] = $this->addmod2n($h[7], $_h);
        }

        // Convert the 32-bit words into human readable hexadecimal format.
        $hexStr = sprintf("%08x%08x%08x%08x%08x%08x%08x%08x", $h[0], $h[1], $h[2], $h[3], $h[4], $h[5], $h[6], $h[7]);

        return ($this->toUpper) ? strtoupper($hexStr) : $hexStr;
    }
    
    function hmac_sha256( $data, $key )
    {
        $pack = 'H64'; //'H'.strlen($this->hash('test'));
        $size = 64;
        $opad = str_repeat(chr(0x5C), $size);
        $ipad = str_repeat(chr(0x36), $size);
    
        if (strlen($key) > $size) {
            $key = str_pad(pack($pack, $this->sha256($key)), $size, chr(0x00));
        } else {
            $key = str_pad($key, $size, chr(0x00));
        }
    
        for ($i = 0; $i < strlen($key) - 1; $i++) {
            $opad[$i] = $opad[$i] ^ $key[$i];
            $ipad[$i] = $ipad[$i] ^ $key[$i];
        }
    
        $output = $this->sha256($opad.pack($pack, $this->sha256($ipad.$data)));
        
        return base64_encode( pack($pack, $output) );
    }
}

class AmazonItemInfo
{
    public $title;
    public $link;
    
    function __construct( $xml )
    {
        if( $xml->Items->Request->IsValid == "False" )
        {
            $this->title = "Invalid Request";
            $this->link = "";
            return;
        }
        
        if( isset( $xml->Items->Request->Errors ) )
        {
            $this->title = "Amazon API failure";
            $this->link = "";
            return;
        }

        $this->title = $xml->Items->Item->ItemAttributes->Title;
        $this->link = $xml->Items->Item->DetailPageURL;
    }
}

class AmazonRequest
{
    private $_appid;
    private $_seckey;
    private $_url;
    
    function __construct( $amzn_appid, $amzn_secret_key, $amzn_url )
    {
        $this->_appid = $amzn_appid;
        $this->_seckey = $amzn_secret_key;
        $this->_url = $amzn_url;
    }
    
    function createParamList( $data )
    {
        ksort( $data );
        
        $req = "";
        foreach( $data as $key => $value )
            $req .= $key . '=' . urlencode($value) . '&';
    
        return substr( $req, 0, strlen($req)-1 );
    }
    
    function createSignature( $data, $key )
    {
        $params = $this->createParamList( $data );
        
        $request = "GET\n".
                   "webservices.amazon.com\n".
                   "/onca/xml\n".
                   $params;

        $obj = new nanoSha2;
        return $obj->hmac_sha256( $request, $key );
    }
    
    function sendRequest( $data )
    {
        $signature = $this->createSignature( $data, $this->_seckey );
        $params = $this->createParamList( $data );
        $sigparam = $this->createParamList( array( 'Signature' => $signature ) );
        $url = $this->_url.'?'.$params.'&'.$sigparam;
        return file_get_contents( $url );
    }
    
    function getItemInfo( $itemid )
    {   
        $data = array(  
            'Service' => 'AWSECommerceService',
            'AWSAccessKeyId' => $this->_appid,
            'Operation' => 'ItemLookup',
            'ItemId' => $itemid,
            'ResponseGroup' => 'Small',
            'Version' => '2009-01-06',
            'Timestamp' => strftime( "%Y-%m-%dT%TZ", time() )
        );
        
        $result = $this->sendRequest( $data );
        
        if( $result === false )
            return false;
            
        $xml = new SimpleXMLElement( $result );
        return new AmazonItemInfo( $xml );
    }
};

/*
$amzn = new AmazonRequest( $_CFG['AMZN_ACCESS_KEY'], $_CFG['AMZN_SECRET_KEY'], $_CFG['AMZN_URL'] );
$item = $amzn->getItemInfo( $data['value'] );
print_r( $item );
*/
?>