phpclassic / php-shopify

PHP SDK for Shopify API
Apache License 2.0
568 stars 211 forks source link

DiscountCode->lookup gets (expected) HTTP header 303 - Sdk throws exception #126

Open NulSEO opened 4 years ago

NulSEO commented 4 years ago

Hi there,

we stumbled upon a small bug while trying to look up a discount code.

DiscountCode->lookUp is expected to receive a "303 See Other", yet, ShopifyResource only handles 200 / 201 in processResponse.

`PHP Fatal error: Uncaught PHPShopify\Exception\CurlException: Request failed with HTTP Code 303. in /var/app/current/vendor/phpclassic/php-shopify/lib/ShopifyResource.php:491 Stack trace:

0 /var/app/current/vendor/phpclassic/php-shopify/lib/ShopifyResource.php(317): PHPShopify\ShopifyResource->processResponse(NULL, 'discount_codes')

1 /var/app/current/vendor/phpclassic/php-shopify/lib/ShopifyResource.php(231): PHPShopify\ShopifyResource->get(Array, 'https://checkou...')

2 /var/app/current/libs/Helpers/DiscountHelper.class.php(16): PHPShopify\ShopifyResource->__call('lookup', Array)

`

tareqtms commented 4 years ago

Can you try the same with direct API call (using Postman or any similar tool)?

NulSEO commented 4 years ago

Yeah, I did:

https://xxxxx.myshopify.com/admin/api/2019-04/discount_codes/lookup.json?code=existingDiscountCode

See: https://help.shopify.com/en/api/reference/discounts/discountcode#lookup-2019-10

So it's an expected behaviour. I suggest either making the response header accessible, or override processRequest in DiscountCode. I can create a pull request if you'd like me to.

Cheers!

suvlime commented 3 years ago

Could be response code 303 treated as a valid on line 539? I will try with something like this:


            $httpOK = 200; //Request Successful, OK.
            $httpCreated = 201; //Create Successful.
            $httpDeleted = 204; //Delete Successful
            $httpSeeOther = 303;

            //should be null if any other library used for http calls
            $httpCode = CurlRequest::$lastHttpCode;

            if ($httpCode != null && $httpCode != $httpOK && $httpCode != $httpCreated && $httpCode != $httpDeleted && $httpCode != $httpSeeOther) {
                throw new Exception\CurlException("Request failed with HTTP Code $httpCode.", $httpCode);
            }`
gfagnani-redstage commented 3 years ago

I would like to follow up on this issue. I'm still getting this error.

Any idea?

Thanks!

suvlime commented 3 years ago

I would like to follow up on this issue. I'm still getting this error.

Any idea?

Thanks!

In the end we did it with native curl. I leave you the example:

function discountCodeLookupRaw($apiKey, $token, $storeUrl, $discountCode){        
        // This would get url for get discount code details        
        $headers = [];
        $url     = sprintf("https://%s:%s@%s/admin/api/2021-01/discount_codes/lookup.json?code=%s", $apiKey, $token, $storeUrl, $discountCode);
        $ch      = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
        curl_setopt($ch, CURLOPT_HEADERFUNCTION,
            function($curl, $header) use (&$headers) {
                $len    = strlen($header);
                $header = explode(':', $header, 2);
                if (count($header) < 2) // ignore invalid headers
                    return $len;

                $name = strtolower(trim($header[0]));

                //getting the location only
                if ($name !== 'location') {
                    return $len;
                }

                if (!array_key_exists($name, $headers))
                    $headers[$name] = [trim($header[1])];
                else
                    $headers[$name][] = trim($header[1]);

                return $len;
            }
        );

        $result    = curl_exec($ch);
        $decodedResult = json_decode($result);        
        if(isset($decodedResult->errors)){
            if(strtolower($decodedResult->errors) == "not found"){
                throw new DiscountCodeNotFound("Discount code " . $discountCode . " not found");
            }
        }
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if (curl_errno($ch) !== 0) {            
            $exception = new \Exception(curl_errno($ch) . " " . $url);
            curl_close($ch);
            throw $exception;
        }

        curl_close($ch);
        $location    = $headers["location"][0];

        $urlDiscount = str_replace($storeUrl , sprintf("%s:%s@%s", $apiKey, $token, $storeUrl), $location);

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $urlDiscount);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
        curl_setopt($ch, CURLOPT_HEADERFUNCTION, function($curl, $header) use (&$headers) {
                $len = strlen($header);
                $header = explode(':', $header, 2);
                if (count($header) < 2) // ignore invalid headers
                    return $len;

                $name = strtolower(trim($header[0]));

                //getting the location only
                if ($name !== 'location') {
                    return $len;
                }

                if (!array_key_exists($name, $headers))
                    $headers[$name] = [trim($header[1])];
                else
                    $headers[$name][] = trim($header[1]);

                return $len;
        });

        $resultDiscount    = curl_exec($ch);
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if (curl_errno($ch) !== 0) {
            $exception = new \Exception(curl_errno($ch) . " " . $urlDiscount);
            curl_close($ch);
            throw $exception;
        }
        curl_close($ch);
        return json_decode($resultDiscount, true);
    }
gfagnani-redstage commented 3 years ago

Sure, it seems the best option for now! Thanks!

lexthor commented 3 years ago

any update on this?