Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
78c31da
Offer createKey() to register a new API key.
rolftimmermans May 30, 2016
d8abbc0
Reuse anonymous client.
rolftimmermans May 30, 2016
e7d975e
Make method public.
rolftimmermans May 30, 2016
94280d1
Use self. [ci skip]
rolftimmermans May 31, 2016
769d98a
Make status public.
rolftimmermans Jun 2, 2016
1befa82
Alternate approach for anonymous clients.
rolftimmermans Jun 22, 2016
c369f9f
Make options protected.
rolftimmermans Jun 22, 2016
8c1a4f1
Merge branch 'master' into create-key
Aug 10, 2016
fc4cc1e
Merge proxy support.
rolftimmermans Jan 3, 2017
f12565c
Merge branch 'master' into create-key
rolftimmermans Jan 18, 2017
fe7e745
Merge branch 'master' into create-key
rolftimmermans Jan 19, 2017
45e79fe
Merge retry logic.
rolftimmermans Feb 24, 2017
7c76bcc
Merge checks for curl/openssl.
rolftimmermans Jul 19, 2017
ce0b3fe
Change ordering and naming.
rolftimmermans Jul 19, 2017
1a927ac
Merge branch 'master' into create-key
mattijsvandruenen Nov 7, 2018
c6b617c
Use keys endpoint for key validation, and added retrieving remaining …
mattijsvandruenen Nov 7, 2018
b21ccb5
Use assertSame instead so that tests also succeed on PHP 7.2.
mattijsvandruenen Nov 7, 2018
cb76e97
Lets indeed not introduce extra alias getters for the new information…
mattijsvandruenen Nov 7, 2018
cd15c07
Merge branch 'master' into create-key
Sep 29, 2021
58652f9
Updated request func not to overwrite request body and created test.
yektaturan Sep 1, 2022
7a005a9
Merge branch 'master' of github.com:wcreateweb/tinify-php into create…
tijmenbruggeman Feb 1, 2025
d71421e
Remove setup
tijmenbruggeman Feb 1, 2025
a2117ce
Remove status check
tijmenbruggeman Feb 4, 2025
093e57b
Merge pull request #38 from wcreateweb/create-key
rkoopmans Feb 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 65 additions & 3 deletions lib/Tinify.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,35 @@
const VERSION = "1.6.2";

class Tinify {
const AUTHENTICATED = true;
const ANONYMOUS = false;

private static $key = NULL;
private static $appIdentifier = NULL;
private static $proxy = NULL;

private static $compressionCount = NULL;
private static $remainingCredits = NULL;
private static $payingState = NULL;
private static $emailAddress = NULL;

private static $client = NULL;

public static function setKey($key) {
self::$key = $key;
self::$client = NULL;
}

public static function getKey() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should use PHP_CodeSniffer or php-cs-fixer to fix PSR-2 coding style.

return self::$key;
}

public static function createKey($email, $options) {
$body = array_merge(array("email" => $email), $options);
$response = self::getClient(self::ANONYMOUS)->request("post", "/keys", $body);
self::setKey($response->body->key);
}

public static function setAppIdentifier($appIdentifier) {
self::$appIdentifier = $appIdentifier;
self::$client = NULL;
Expand All @@ -35,8 +52,32 @@ public static function setCompressionCount($compressionCount) {
self::$compressionCount = $compressionCount;
}

public static function getClient() {
if (!self::$key) {
public static function getRemainingCredits() {
return self::$remainingCredits;
}

public static function setRemainingCredits($remainingCredits) {
self::$remainingCredits = $remainingCredits;
}

public static function getPayingState() {
return self::$payingState;
}

public static function setPayingState($payingState) {
self::$payingState = $payingState;
}

public static function getEmailAddress() {
return self::$emailAddress;
}

public static function setEmailAddress($emailAddress) {
self::$emailAddress = $emailAddress;
}

public static function getClient($mode = self::AUTHENTICATED) {
if ($mode == self::AUTHENTICATED && !self::$key) {
throw new AccountException("Provide an API key with Tinify\setKey(...)");
}

Expand All @@ -56,6 +97,14 @@ function setKey($key) {
return Tinify::setKey($key);
}

function getKey() {
return Tinify::getKey();
}

function createKey($email, $options) {
return Tinify::createKey($email, $options);
}

function setAppIdentifier($appIdentifier) {
return Tinify::setAppIdentifier($appIdentifier);
}
Expand All @@ -72,6 +121,18 @@ function compressionCount() {
return Tinify::getCompressionCount();
}

function remainingCredits() {
return Tinify::getRemainingCredits();
}

function payingState() {
return Tinify::getPayingState();
}

function emailAddress() {
return Tinify::getEmailAddress();
}

Copy link

@peter279k peter279k Nov 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These methods are very strange.

They looks similar. The duplicate should be removed.

function fromFile($path) {
return Source::fromFile($path);
}
Expand All @@ -86,7 +147,8 @@ function fromUrl($string) {

function validate() {
try {
Tinify::getClient()->request("post", "/shrink");
Tinify::getClient()->request("get", "/keys/" . Tinify::getKey());
return true;
} catch (AccountException $err) {
if ($err->status == 429) return true;
throw $err;
Expand Down
67 changes: 55 additions & 12 deletions lib/Tinify/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class Client {
const RETRY_COUNT = 1;
const RETRY_DELAY = 500;

private $options;
protected $options;

public static function userAgent() {
$curl = curl_version();
Expand All @@ -19,7 +19,7 @@ private static function caBundle() {
return __DIR__ . "/../data/cacert.pem";
}

function __construct($key, $app_identifier = NULL, $proxy = NULL) {
function __construct($key, $appIdentifier = NULL, $proxy = NULL) {
$curl = curl_version();

if (!($curl["features"] & CURL_VERSION_SSL)) {
Expand All @@ -31,13 +31,15 @@ function __construct($key, $app_identifier = NULL, $proxy = NULL) {
throw new ClientException("Your curl version {$version} is outdated; please upgrade to 7.18.1 or higher");
}

$userAgent = join(" ", array_filter(array(self::userAgent(), $appIdentifier)));

$this->options = array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true,
CURLOPT_USERPWD => "api:" . $key,
CURLOPT_USERPWD => $key ? ("api:" . $key) : NULL,
CURLOPT_CAINFO => self::caBundle(),
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_USERAGENT => join(" ", array_filter(array(self::userAgent(), $app_identifier))),
CURLOPT_USERAGENT => $userAgent,
);

if ($proxy) {
Expand Down Expand Up @@ -111,12 +113,16 @@ function request($method, $url, $body = NULL) {
$headers = self::parseHeaders(substr($response, 0, $headerSize));
$responseBody = substr($response, $headerSize);

if (isset($headers["compression-count"])) {
if ( isset($headers["compression-count"] ) ) {
Tinify::setCompressionCount(intval($headers["compression-count"]));
}

if ($status >= 200 && $status <= 299) {
return (object) array("body" => $responseBody, "headers" => $headers);
if ( isset( $headers["compression-count-remaining"] ) ) {
Tinify::setRemainingCredits( intval( $headers["compression-count-remaining"] ) );
}

if ( isset( $headers["paying-state"] ) ) {
Tinify::setPayingState( $headers["paying-state"] );
}

$details = json_decode($responseBody);
Expand All @@ -130,8 +136,45 @@ function request($method, $url, $body = NULL) {
);
}

if ($retries > 0 && $status >= 500) continue;
throw Exception::create($details->message, $details->error, $status);
if ( isset( $headers["email-address"] ) ) {
Tinify::setEmailAddress( $headers["email-address"] );
}

$isJson = false;
if (isset($headers["content-type"])) {
/* Parse JSON response bodies. */
list($contentType) = explode(";", $headers["content-type"], 2);
if (strtolower(trim($contentType)) == "application/json") {
$isJson = true;
}
}

/* 1xx and 3xx are unexpected and will be treated as error. */
$isError = $status <= 199 || $status >= 300;

if ($isJson || $isError) {
/* Parse JSON bodies, always interpret errors as JSON. */
$responseBody = json_decode($responseBody);
if (!$responseBody) {
$message = sprintf("Error while parsing response: %s (#%d)",
PHP_VERSION_ID >= 50500 ? json_last_error_msg() : "Error",
json_last_error());
if ($retries > 0 && $status >= 500) continue;
throw Exception::create($message, "ParseError", $status);
}
}

if ($isError) {
if ($retries > 0 && $status >= 500) continue;
/* When the key doesn't exist a 404 response is given. */
if ($status == 404) {
throw Exception::create(null, null, $status);
} else {
throw Exception::create($responseBody->message, $responseBody->error, $status);
}
}

return (object) array("body" => $responseBody, "headers" => $headers);
} else {
$message = sprintf("%s (#%d)", curl_error($request), curl_errno($request));
curl_close($request);
Expand All @@ -146,14 +189,14 @@ protected static function parseHeaders($headers) {
$headers = explode("\r\n", $headers);
}

$res = array();
$result = array();
foreach ($headers as $header) {
if (empty($header)) continue;
$split = explode(":", $header, 2);
if (count($split) === 2) {
$res[strtolower($split[0])] = trim($split[1]);
$result[strtolower($split[0])] = trim($split[1]);
}
}
return $res;
return $result;
}
}
2 changes: 1 addition & 1 deletion lib/Tinify/Exception.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class Exception extends \Exception {
public $status;

public static function create($message, $type, $status) {
if ($status == 401 || $status == 429) {
if ($status == 401 || $status == 403 || $status == 404 || $status == 429) {
$klass = "Tinify\AccountException";
} else if($status >= 400 && $status <= 499) {
$klass = "Tinify\ClientException";
Expand Down
70 changes: 70 additions & 0 deletions test/TinifyClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,36 @@ public function testRequestWhenValidShouldUpdateCompressionCount() {
$this->assertSame(12, Tinify\getCompressionCount());
}

public function testRequestWhenValidShouldUpdateRemainingCredits() {
CurlMock::register("https://api.tinify.com/", array(
"status" => 200, "headers" => array("Compression-Count-Remaining" => "488")
));
$client = new Tinify\Client("key");
$client->request("get", "/");

$this->assertSame(488, Tinify\remainingCredits());
}

public function testRequestWhenValidShouldUpdatePayingState() {
CurlMock::register("https://api.tinify.com/", array(
"status" => 200, "headers" => array("Paying-State" => "free")
));
$client = new Tinify\Client("key");
$client->request("get", "/");

$this->assertSame("free", Tinify\payingState());
}

public function testRequestWhenValidShouldUpdateEmailAddress() {
CurlMock::register("https://api.tinify.com/", array(
"status" => 200, "headers" => array("Email-Address" => "test@example.com")
));
$client = new Tinify\Client("key");
$client->request("get", "/");

$this->assertSame("test@example.com", Tinify\emailAddress());
}

public function testRequestWhenValidWithAppIdShouldIssueRequestWithUserAgent() {
CurlMock::register("https://api.tinify.com/", array("status" => 200));
$client = new Tinify\Client("key", "TestApp/0.1");
Expand All @@ -63,6 +93,29 @@ public function testRequestWhenValidWithAppIdShouldIssueRequestWithUserAgent() {
$this->assertSame(Tinify\Client::userAgent() . " TestApp/0.1", CurlMock::last(CURLOPT_USERAGENT));
}

public function testRequestWhenValidShouldParseJSONBody() {
CurlMock::register("https://api.tinify.com/", array(
"status" => 200,
"body" => '{"hello":"world"}',
"headers" => array("Content-Type" => "application/JSON; charset=utf-8")
));
$client = new Tinify\Client("key");
$response = $client->request("post", "/");
$this->assertSame("world", $response->body->hello);
}

public function testRequestWhenValidShouldNotParseBinaryBody() {
CurlMock::register("https://api.tinify.com/", array(
"status" => 200,
"body" => "binary body",
"headers" => array("Content-Type" => "image/png")
));
$client = new Tinify\Client("key");
$response = $client->request("post", "/");

$this->assertSame("binary body", $response->body);
}

public function testRequestWhenValidWithProxyShouldIssueRequestWithProxyAuthorization() {
CurlMock::register("https://api.tinify.com/", array("status" => 200));
$client = new Tinify\Client("key", NULL, "http://user:pass@localhost:8080");
Expand All @@ -73,6 +126,23 @@ public function testRequestWhenValidWithProxyShouldIssueRequestWithProxyAuthoriz
$this->assertSame("user:pass", CurlMock::last(CURLOPT_PROXYUSERPWD));
}

public function testRequestWithBadJSONBodyThrowExceptionWithMessage() {
CurlMock::register("https://api.tinify.com/", array(
"status" => 200,
"body" => '<!-- this is not json -->',
"headers" => array("Content-Type" => "application/JSON"),
));
if (PHP_VERSION_ID >= 50500) {
$this->setExpectedExceptionRegExp("Tinify\Exception",
"/Error while parsing response: Syntax error \(#4\) \(HTTP 200\/ParseError\)/");
} else {
$this->setExpectedExceptionRegExp("Tinify\Exception",
"/Error while parsing response: Error \(#4\) \(HTTP 200\/ParseError\)/");
}
$client = new Tinify\Client("key");
$client->request("get", "/");
}

public function testRequestWithUnexpectedErrorOnceShouldReturnResponse() {
CurlMock::register("https://api.tinify.com/", array(
"error" => "Failed!", "errno" => 2
Expand Down
13 changes: 13 additions & 0 deletions test/TinifyExceptionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

class TinifyExceptionTest extends TestCase {
public function testStatusShouldReturnStatusIfSet() {
$err = new Tinify\Exception("Message", "Error", 401);
$this->assertSame(401, $err->status);
}

public function testStatusShouldReturnNullIfUnset() {
$err = new Tinify\Exception("Message", "Error");
$this->assertSame(null, $err->status);
}
}
Loading