title: Converting Python API request to cURL PHP request
body: <p>I apologize if this has been asked or has a similar questions; I have been searching for days using different search terms and have come up empty.</p>
  <p>I have a python script that works perfectly fine as expected. I have it installed on my windows machine and run the script locally. What I want to do is somehow convert this to a PHP request; I assumed cURL would be the option selected but I am open to suggestions. I have made a couple attempts on my end, but I keep getting an authentication error. I'm sure it's something simple; but maybe not.</p>
  <p>Here is my python script:</p>
  <pre><code>import requests
  from datetime import datetime
  import hashlib
  import hmac
  import base64
  import json
  import time
  
  def main():    
      api_key = 'abcd'
      secret_key = 'hashedSecret'
      host = 'https://myapidomain.com/'
      uri = 'api/1.0/Projects/8030854199/items'
  
      http_verb = 'GET'
      content_type = 'application/json'
      timestamp = gen_iso_timestamp()
      auth_header_value = gen_auth_string(api_key, secret_key, uri, http_verb, content_type, timestamp)
      full_url = f'{host}{uri}'
      headers = {'att-api-timestamp': timestamp, 'authorization': auth_header_value, 'Content-Type': content_type, 'Accept': content_type}
      
      r = requests.get(full_url, headers=headers)
      if r.status_code == 200:
          with open(f'data_dump/8030854199.json', 'w+') as json_file:
              json_file.write(r.text)
      elif r.status_code != 200:
          error_code = f'{r.status_code}'
          with open(f'data_dump/error.txt', 'w+') as json_file:
              json_file.write(error_code)
  
  
  def gen_auth_string(api_key, secret_key, uri, http_verb, content_type, timestamp):
      message = f'{http_verb}\n{content_type}\n{uri}\n{timestamp}'
      canonical_request = bytes(message, 'ASCII')
      secret_bytes = bytes(secret_key, 'ASCII')
      digest = hmac.new(secret_bytes, msg=canonical_request, digestmod=hashlib.sha256).digest()
      signature = base64.b64encode(digest).decode()
      return f'AttAPI {api_key}:{signature}'
  
  
  def gen_iso_timestamp():
      # generate a timestamp in this format 2018-12-31T23:55:55+00:00
      return f'{datetime.utcnow().replace(microsecond=0).isoformat()}+00:00'
  
  
  if __name__ == &quot;__main__&quot;:
      main()
  </code></pre>
  <p>Here was my test PHP code:</p>
  <pre><code>&lt;?php
  
  function genTimestamp(){ return gmdate(DATE_ATOM); }
  function genAuthString($secret_key, $uri, $timestamp){ 
      $message = &quot;GET&quot;.&quot;\n&quot;.&quot;application/json&quot;.&quot;\n&quot;.$uri.&quot;\n&quot;.$timestamp;
      return hash_hmac('sha256',$message,$secret_key,true);
  }
  
  $api_key = 'abcd';
  $secret_key = 'hashedSecret';
  $host = 'https://myapidomain.com/';
  $uri = 'api/1.0/Projects/8030854199/items';
  $timestamp = genTimestamp();
  // for testing: 
  //    echo $timestamp.&quot;&lt;br /&gt;&quot;;
  
  $curl = curl_init();
  
  curl_setopt($curl, CURLOPT_URL, $host.$uri);
  curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 0);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET');
  curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
  curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
  // for testing: 
  //    echo genAuthString($secret_key, $uri, $timestamp).&quot;&lt;br /&gt;&quot;
  curl_setopt($curl, CURLOPT_HTTPHEADER, array(
      'att-api-timestamp: '.$timestamp,
      'authorization: '.genAuthString($secret_key, $uri, $timestamp),
      'Content-Type: application/json',
      'Accept: application/json'
  ));
  
  // for testing: 
  //    echo &quot;Executing... &lt;br /&gt;&quot;;
  $result = curl_exec($curl);
  if (curl_errno($curl)) {
      // for testing: 
      echo 'Error:' . curl_error($curl) . &quot;&lt;br /&gt;&quot;;
  }
  curl_close($curl);
  echo $result;
  
  ?&gt;
  </code></pre>
  <p>Note that the timestamp must be stored in a variable to be hashed in the HMAC and sent as a header or else it definitely won't authenticate.</p>
  <p>Any guidance or suggestions would be greatly appreciated!</p>
  <p>Thanks</p>