tinypng: init

This commit is contained in:
onli 2016-10-16 12:12:58 +02:00
parent b9bec3f831
commit 43f167becd
14 changed files with 4546 additions and 0 deletions

View file

@ -0,0 +1,6 @@
<?php #
@define('PLUGIN_EVENT_TINYPNG_NAME', 'Compress Images');
@define('PLUGIN_EVENT_TINYPNG_DESC', 'Compress PNG and JPG images with the TinyPNG service.');
@define('PLUGIN_EVENT_TINYPNG_APIKEY', 'TinyPNG API key');
@define('PLUGIN_EVENT_TINYPNG_APIKEY_DESC', 'API key for tinypng, register at https://tinypng.com/developers.');

View file

@ -0,0 +1,6 @@
<?php #
@define('PLUGIN_EVENT_TINYPNG_NAME', 'Compress Images');
@define('PLUGIN_EVENT_TINYPNG_DESC', 'Compress PNG and JPG images with the TinyPNG service.');
@define('PLUGIN_EVENT_TINYPNG_APIKEY', 'TinyPNG API key');
@define('PLUGIN_EVENT_TINYPNG_APIKEY_DESC', 'API key for tinypng, register at https://tinypng.com/developers.');

View file

@ -0,0 +1,86 @@
<?php
if (IN_serendipity !== true) {
die ("Don't hack!");
}
@serendipity_plugin_api::load_language(dirname(__FILE__));
class serendipity_event_tinypng extends serendipity_event {
var $title = PLUGIN_EVENT_TINYPNG_NAME;
function introspect(&$propbag) {
global $serendipity;
$propbag->add('name', PLUGIN_EVENT_TINYPNG_NAME);
$propbag->add('description', PLUGIN_EVENT_TINYPNG_DESC);
$propbag->add('stackable', false);
$propbag->add('author', 'onli');
$propbag->add('version', '0.1');
$propbag->add('requirements', array(
'serendipity' => '2.0'
));
$propbag->add('event_hooks', array('backend_image_add' => true));
$propbag->add('groups', array('IMAGES'));
$propbag->add('configuration', array('tinypngkey'));
}
function generate_content(&$title) {
$title = $this->title;
}
function introspect_config_item($name, &$propbag) {
global $serendipity;
switch($name) {
case 'tinypngkey':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_EVENT_TINYPNG_APIKEY);
$propbag->add('description', PLUGIN_EVENT_TINYPNG_APIKEY_DESC);
$propbag->add('default', 'none');
break;
}
return true;
}
function event_hook($event, &$bag, &$eventData, $addData = null) {
global $serendipity;
$hooks = &$bag->get('event_hooks');
if (isset($hooks[$event])) {
switch($event) {
case 'backend_image_add':
require_once("tinify-php/lib/Tinify/Exception.php");
require_once("tinify-php/lib/Tinify/ResultMeta.php");
require_once("tinify-php/lib/Tinify/Result.php");
require_once("tinify-php/lib/Tinify/Source.php");
require_once("tinify-php/lib/Tinify/Client.php");
require_once("tinify-php/lib/Tinify.php");
Tinify\setKey($this->get_config("tinypngkey"));
$image = $eventData;
if (substr($image, -4) == ".png" || substr($image, -4) == ".jpg") {
$thumbnail = str_replace(".jpg", ".serendipityThumb.jpg", $image);
$thumbnail = str_replace(".png", ".serendipityThumb.png", $thumbnail);
Tinify\fromFile($image)->toFile($image);
Tinify\fromFile($thumbnail)->toFile($thumbnail);
}
break;
default:
return false;
}
} else {
return false;
}
}
}
/* vim: set sts=4 ts=4 expandtab : */
?>

View file

@ -0,0 +1 @@
vendor

View file

@ -0,0 +1,25 @@
language: php
php:
- 5.3
- 5.4
- 5.5
- 5.6
- 7.0
- hhvm
- nightly
env:
global:
secure: BFdcLqU/07l3/NGaSZA5+VSB5FSVSwTL9wAyrJSD1N7jN2HzFTE4xxxmcVrAqq6t+jhZqajXcSf8/DTUKyLcmWXGw3JkseHx3ofHw5p2E4Mp+dUvNMh+3KgAABCPm5zEBUgnhNGwFqL+WA/cgXIJY1/sv87u/mg63ojvf3orKJ3KMxFFsVbGo553XYVsiSUXfzvV3foqPdcV9D0SZ0v7IiLcsuwtDRtfJ/udgSZ2C2LFiOek1dLwbjM3inMBPkfLcpuvC2l8Z1CyW5ptxYRrHHJqCMbdRmmwGH04hxRju54EJKX5PGTyDhfG9Kyiu8/hQCtDL4jNQlVNAKbvHrRTnLogoMKhHMRaAIDMNI+lcQB9OHHuureYAqL7gJvRmE2sfN/OAbzizYJ2z+yXvjaKJsd2htrHff8hgvl0M3guhP+mA5C9ubibzGiCD66kdeqS5tJi3EH7wk9GO75lFm3tlZEWZ4FJCwgyFQRZGMGSRJC5cWvW4QlGLHeVnWwnf9CM9/B2oD21LraccgCZhpIbib5/XJ2vTQO0V2ke3kXT1D9E3P8E2eClxnge1aShUSy+d5kMTNeLxkfalgGEviWqA236XLzS8+MjWzNWy3+roBb63Vh0OPp4GyTO810U16Y5lwCMegVrxusnz9bCo1HbK1w2k8D7Ueb/O7LEFYaZSD4=
matrix:
allow_failures:
- php: nightly
include:
- php: 5.6
env: INTEGRATION_TESTS=true
script: "if [ \"$TRAVIS_PULL_REQUEST\" == \"false\" ]; then vendor/bin/phpunit --no-configuration test/integration.php; fi"
before_script: composer install
script: vendor/bin/phpunit
notifications:
email: false
slack:
secure: W1cEp+ctAD+in3hA/gansbUYrFZsR3EMd7s/XiK2mfAxRRXPCPgCvv0PWpYelJ5F2AnHXkmBP3USKFDhKN+JLmOOxrZpjzh4ve9QSNs4IPgcrU4meQYSgJ3uovS7h4fqAmqhQKL+FpAnrXAmXWGXVPCPtneySsMTyU6kNdmVfulxXRMJ+kLHtFQlT+U7cPYG0f8FkKR2u5CbRsdjUvoZHwbK7jmWpUcCi2O0A1vvMMEMEOG+iuayWW/RbfSfKIgM/SZG0pGYpoAB7I8XfYns7IyLhkJAw18jIWnowF4DuBusNRdr3zIfwC7bSlLKMFYJYpEsiLFCaeGZgp1NbYJ77DvqpwNp9xmoPz9rFGNe7Re+i13pjNWhEnwc5N3St7x8DYNhUC3L0upQ2FWZSomMM7ghlc6GIVtlXYrRJ5AnxIjSWyLRcTRU5Pf/PPRckOTiuLnVgUZNMVIlAHlRV7c/pUVDjbPvjcOajdXnpcd3+5cuKyzCYpXugIfJ9Hzsozq0yCHDKjo8ssAU+5H3mEfB7M25Rtd2awObb3zqOyUPm+J3M/dzql95cF+zj2SWQsBF/ViwkHo+9SoAr/FYqCZveiS0w9vzoKzbGXVDYCfFD+GlEMJ2b8zw4d2sqmIbw24jGq1ZPgczrpD5fcbI2TaheKBkgWvsBJFFO5KbGWqzHIM=

View file

@ -0,0 +1,21 @@
The MIT License
Copyright (c) 2013-2016 Voormedia
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.

View file

@ -0,0 +1,58 @@
[<img src="https://travis-ci.org/tinify/tinify-php.svg?branch=master" alt="Build Status">](https://travis-ci.org/tinify/tinify-php)
# Tinify API client for PHP
PHP client for the Tinify API, used for [TinyPNG](https://tinypng.com) and [TinyJPG](https://tinyjpg.com). Tinify compresses your images intelligently. Read more at [http://tinify.com](http://tinify.com).
## Documentation
[Go to the documentation for the PHP client](https://tinypng.com/developers/reference/php).
## Installation
Install the API client with Composer. Add this to your `composer.json`:
```json
{
"require": {
"tinify/tinify": "*"
}
}
```
Then install with:
```
composer install
```
Use autoloading to make the client available in PHP:
```php
require_once("vendor/autoload.php");
```
## Usage
```php
Tinify\setKey("YOUR_API_KEY");
Tinify\fromFile("unoptimized.png")->toFile("optimized.png");
```
## Running tests
```
composer install
vendor/bin/phpunit
```
### Integration tests
```
composer install
TINIFY_KEY=$YOUR_API_KEY vendor/bin/phpunit --no-configuration test/integration.php
```
## License
This software is licensed under the MIT License. [View the license](LICENSE).

View file

@ -0,0 +1,85 @@
<?php
namespace Tinify;
const VERSION = "1.3.0";
class Tinify {
private static $key = NULL;
private static $appIdentifier = NULL;
private static $compressionCount = NULL;
private static $client = NULL;
public static function setKey($key) {
self::$key = $key;
self::$client = NULL;
}
public static function setAppIdentifier($appIdentifier) {
self::$appIdentifier = $appIdentifier;
self::$client = NULL;
}
public static function getCompressionCount() {
return self::$compressionCount;
}
public static function setCompressionCount($compressionCount) {
self::$compressionCount = $compressionCount;
}
public static function getClient() {
if (!self::$key) {
throw new AccountException("Provide an API key with Tinify\setKey(...)");
}
if (!self::$client) {
self::$client = new Client(self::$key, self::$appIdentifier);
}
return self::$client;
}
public static function setClient($client) {
self::$client = $client;
}
}
function setKey($key) {
return Tinify::setKey($key);
}
function setAppIdentifier($appIdentifier) {
return Tinify::setAppIdentifier($appIdentifier);
}
function getCompressionCount() {
return Tinify::getCompressionCount();
}
function compressionCount() {
return Tinify::getCompressionCount();
}
function fromFile($path) {
return Source::fromFile($path);
}
function fromBuffer($string) {
return Source::fromBuffer($string);
}
function fromUrl($string) {
return Source::fromUrl($string);
}
function validate() {
try {
Tinify::getClient()->request("post", "/shrink");
} catch (AccountException $err) {
if ($err->status == 429) return true;
throw $err;
} catch (ClientException $err) {
return true;
}
}

View file

@ -0,0 +1,108 @@
<?php
namespace Tinify;
class Client {
const API_ENDPOINT = "https://api.tinify.com";
private $options;
public static function userAgent() {
$curl = curl_version();
return "Tinify/" . VERSION . " PHP/" . PHP_VERSION . " curl/" . $curl["version"];
}
private static function caBundle() {
return __DIR__ . "/../data/cacert.pem";
}
function __construct($key, $app_identifier = NULL) {
$this->options = array(
CURLOPT_BINARYTRANSFER => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true,
CURLOPT_USERPWD => "api:" . $key,
CURLOPT_CAINFO => self::caBundle(),
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_USERAGENT => join(" ", array_filter(array(self::userAgent(), $app_identifier))),
);
}
function request($method, $url, $body = NULL, $header = array()) {
if (is_array($body)) {
if (!empty($body)) {
$body = json_encode($body);
array_push($header, "Content-Type: application/json");
} else {
$body = NULL;
}
}
$request = curl_init();
curl_setopt_array($request, $this->options);
$url = strtolower(substr($url, 0, 6)) == "https:" ? $url : Client::API_ENDPOINT . $url;
curl_setopt($request, CURLOPT_URL, $url);
curl_setopt($request, CURLOPT_CUSTOMREQUEST, strtoupper($method));
if (count($header) > 0) {
curl_setopt($request, CURLOPT_HTTPHEADER, $header);
}
if ($body) {
curl_setopt($request, CURLOPT_POSTFIELDS, $body);
}
$response = curl_exec($request);
if (is_string($response)) {
$status = curl_getinfo($request, CURLINFO_HTTP_CODE);
$headerSize = curl_getinfo($request, CURLINFO_HEADER_SIZE);
curl_close($request);
$headers = self::parseHeaders(substr($response, 0, $headerSize));
$body = substr($response, $headerSize);
if (isset($headers["compression-count"])) {
Tinify::setCompressionCount(intval($headers["compression-count"]));
}
if ($status >= 200 && $status <= 299) {
return array("body" => $body, "headers" => $headers);
}
$details = json_decode($body);
if (!$details) {
$message = sprintf("Error while parsing response: %s (#%d)",
PHP_VERSION_ID >= 50500 ? json_last_error_msg() : "Error",
json_last_error());
$details = (object) array(
"message" => $message,
"error" => "ParseError"
);
}
throw Exception::create($details->message, $details->error, $status);
} else {
$message = sprintf("%s (#%d)", curl_error($request), curl_errno($request));
curl_close($request);
throw new ConnectionException("Error while connecting: " . $message);
}
}
protected static function parseHeaders($headers) {
if (!is_array($headers)) {
$headers = explode("\r\n", $headers);
}
$res = array();
foreach ($headers as $header) {
if (empty($header)) continue;
$split = explode(":", $header, 2);
if (count($split) === 2) {
$res[strtolower($split[0])] = trim($split[1]);
}
}
return $res;
}
}

View file

@ -0,0 +1,34 @@
<?php
namespace Tinify;
class Exception extends \Exception {
public static function create($message, $type, $status) {
if ($status == 401 || $status == 429) {
$klass = "Tinify\AccountException";
} else if($status >= 400 && $status <= 499) {
$klass = "Tinify\ClientException";
} else if($status >= 500 && $status <= 599) {
$klass = "Tinify\ServerException";
} else {
$klass = "Tinify\Exception";
}
if (empty($message)) $message = "No message was provided";
return new $klass($message, $type, $status);
}
function __construct($message, $type = NULL, $status = NULL) {
if ($status) {
$this->status = $status;
parent::__construct($message . " (HTTP " . $status . "/" . $type . ")");
} else {
parent::__construct($message);
}
}
}
class AccountException extends Exception {}
class ClientException extends Exception {}
class ServerException extends Exception {}
class ConnectionException extends Exception {}

View file

@ -0,0 +1,36 @@
<?php
namespace Tinify;
class Result extends ResultMeta {
protected $data;
public function __construct($meta, $data) {
$this->meta = $meta;
$this->data = $data;
}
public function data() {
return $this->data;
}
public function toBuffer() {
return $this->data;
}
public function toFile($path) {
return file_put_contents($path, $this->toBuffer());
}
public function size() {
return intval($this->meta["content-length"]);
}
public function mediaType() {
return $this->meta["content-type"];
}
public function contentType() {
return $this->mediaType();
}
}

View file

@ -0,0 +1,23 @@
<?php
namespace Tinify;
class ResultMeta {
protected $meta;
public function __construct($meta) {
$this->meta = $meta;
}
public function width() {
return intval($this->meta["image-width"]);
}
public function height() {
return intval($this->meta["image-height"]);
}
public function location() {
return isset($this->meta["location"]) ? $this->meta["location"] : null;
}
}

View file

@ -0,0 +1,69 @@
<?php
namespace Tinify;
class Source {
private $url, $commands;
public static function fromFile($path) {
return self::fromBuffer(file_get_contents($path));
}
public static function fromBuffer($string) {
$response = Tinify::getClient()->request("post", "/shrink", $string);
return new self($response["headers"]["location"]);
}
public static function fromUrl($url) {
$body = array("source" => array("url" => $url));
$response = Tinify::getClient()->request("post", "/shrink", $body);
return new self($response["headers"]["location"]);
}
public function __construct($url, $commands = array()) {
$this->url = $url;
$this->commands = $commands;
}
public function preserve() {
$options = $this->flatten(func_get_args());
$commands = array_merge($this->commands, array("preserve" => $options));
return new self($this->url, $commands);
}
public function resize($options) {
$commands = array_merge($this->commands, array("resize" => $options));
return new self($this->url, $commands);
}
public function store($options) {
$response = Tinify::getClient()->request("post", $this->url,
array_merge($this->commands, array("store" => $options)));
return new Result($response["headers"], $response["body"]);
}
public function result() {
$response = Tinify::getClient()->request("get", $this->url, $this->commands);
return new Result($response["headers"], $response["body"]);
}
public function toFile($path) {
return $this->result()->toFile($path);
}
public function toBuffer() {
return $this->result()->toBuffer();
}
private static function flatten($options) {
$flattened = array();
foreach ($options as $option) {
if (is_array($option)) {
$flattened = array_merge($flattened, $option);
} else {
array_push($flattened, $option);
}
}
return $flattened;
}
}

File diff suppressed because it is too large Load diff