This commit is contained in:
Elix 2023-01-04 15:38:17 +01:00 committed by GitHub
commit 56f3c086c2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 203 additions and 85 deletions

View file

@ -1,6 +1,6 @@
<?php
//
// SimpleImage v3.6.3
// SimpleImage
//
// A PHP class that makes working with images as simple as possible.
//
@ -31,7 +31,8 @@ class SimpleImage {
ERR_LIB_NOT_LOADED = 8,
ERR_UNSUPPORTED_FORMAT = 9,
ERR_WEBP_NOT_ENABLED = 10,
ERR_WRITE = 11;
ERR_WRITE = 11,
ERR_INVALID_FLAG = 12;
protected $image;
@ -46,9 +47,10 @@ class SimpleImage {
* Creates a new SimpleImage object.
*
* @param string $image An image file or a data URI to load.
* @param array $flags Optional override of default flags.
* @throws \Exception Thrown if the GD library is not found; file|URI or image data is invalid.
*/
public function __construct($image = null) {
public function __construct($image = '', $flags = []) {
// Check for the required GD extension
if(extension_loaded('gd')) {
// Ignore JPEG warnings that cause imagecreatefromjpeg() to fail
@ -57,6 +59,16 @@ class SimpleImage {
throw new \Exception('Required extension GD is not loaded.', self::ERR_GD_NOT_ENABLED);
}
// Associative array of flags.
$this->flags = [
"sslVerify" => true // Skip SSL peer validation
];
// Override default flag values.
foreach($flags as $flag => $value) {
$this->setFlag($flag, $value);
}
// Load an image through the constructor
if(preg_match('/^data:(.*?);/', $image)) {
$this->fromDataUri($image);
@ -77,6 +89,37 @@ class SimpleImage {
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////
// Helper functions
//////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Set flag value.
*
* @param string $flag Name of the flag to set.
* @param boolean $value State of the flag.
* @throws \Exception Thrown if flag does not exist (no default value).
*/
public function setFlag($flag, $value) {
// Throw if flag does not exist
if(!in_array($flag, array_keys($this->flags))) {
throw new \Exception('Invalid flag.', self::ERR_INVALID_FLAG);
}
// Set flag value by name
$this->flags[$flag] = $value;
}
/**
* Get flag value.
*
* @param string $flag Name of the flag to get.
* @return boolean|null
*/
public function getFlag($flag) {
return in_array($flag, array_keys($this->flags)) ? $this->flags[$flag] : null;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
// Loaders
//////////////////////////////////////////////////////////////////////////////////////////////////
@ -118,70 +161,66 @@ class SimpleImage {
* Loads an image from a file.
*
* @param string $file The image file to load.
* @param boolean $sslVerify Set to false to skip SSL validation.
* @throws \Exception Thrown if file or image data is invalid.
* @return \claviska\SimpleImage
*/
public function fromFile($file) {
// Check if the file exists and is readable. We're using fopen() instead of file_exists()
// because not all URL wrappers support the latter.
$handle = @fopen($file, 'r');
if($handle === false) {
// Set fopen options.
$sslVerify = $this->getFlag("sslVerify"); // Don't perform peer validation when true
$opts = [
"ssl" => [
"verify_peer" => $sslVerify,
"verify_peer_name" => $sslVerify
]
];
// Check if the file exists and is readable.
$file = @file_get_contents($file, false, stream_context_create($opts));
if($file === false) {
throw new \Exception("File not found: $file", self::ERR_FILE_NOT_FOUND);
}
fclose($handle);
// Create image object from string
$this->image = imagecreatefromstring($file);
// Get image info
$info = @getimagesize($file);
$info = @getimagesizefromstring($file);
if($info === false) {
throw new \Exception("Invalid image file: $file", self::ERR_INVALID_IMAGE);
}
$this->mimeType = $info['mime'];
// Create image object from file
switch($this->mimeType) {
case 'image/gif':
// Load the gif
$gif = imagecreatefromgif($file);
if($gif) {
// Copy the gif over to a true color image to preserve its transparency. This is a
// workaround to prevent imagepalettetruecolor() from borking transparency.
$width = imagesx($gif);
$height = imagesy($gif);
$this->image = imagecreatetruecolor($width, $height);
$transparentColor = imagecolorallocatealpha($this->image, 0, 0, 0, 127);
imagecolortransparent($this->image, $transparentColor);
imagefill($this->image, 0, 0, $transparentColor);
imagecopy($this->image, $gif, 0, 0, 0, 0, $width, $height);
imagedestroy($gif);
}
break;
case 'image/jpeg':
$this->image = imagecreatefromjpeg($file);
break;
case 'image/png':
$this->image = imagecreatefrompng($file);
break;
case 'image/webp':
$this->image = imagecreatefromwebp($file);
break;
case 'image/bmp':
case 'image/x-ms-bmp':
case 'image/x-windows-bmp':
$this->image = imagecreatefrombmp($file);
break;
}
if(!$this->image) {
throw new \Exception("Unsupported format: " . $this->mimeType, self::ERR_UNSUPPORTED_FORMAT);
}
switch($this->mimeType) {
case 'image/gif':
// Copy the gif over to a true color image to preserve its transparency. This is a
// workaround to prevent imagepalettetotruecolor() from borking transparency.
$width = imagesx($this->image);
$height = imagesx($this->image);
$gif = imagecreatetruecolor((int) $width, (int) $height);
$alpha = imagecolorallocatealpha($gif, 0, 0, 0, 127);
imagecolortransparent($gif, $alpha);
imagefill($gif, 0, 0, $alpha);
imagecopy($this->image, $gif, 0, 0, 0, 0, $width, $height);
imagedestroy($gif);
break;
case 'image/jpeg':
// Load exif data from JPEG images
if(function_exists('exif_read_data')) {
$this->exif = @exif_read_data("data://image/jpeg;base64," . base64_encode($file));
}
break;
}
// Convert pallete images to true color images
imagepalettetotruecolor($this->image);
// Load exif data from JPEG images
if($this->mimeType === 'image/jpeg' && function_exists('exif_read_data')) {
$this->exif = @exif_read_data($file);
}
return $this;
}
@ -194,7 +233,7 @@ class SimpleImage {
* @return \claviska\SimpleImage
*/
public function fromNew($width, $height, $color = 'transparent') {
$this->image = imagecreatetruecolor($width, $height);
$this->image = imagecreatetruecolor((int) $width, (int) $height);
// Use PNG for dynamically created images because it's lossless and supports transparency
$this->mimeType = 'image/png';
@ -490,7 +529,7 @@ class SimpleImage {
imagefilter($srcIm, IMG_FILTER_COLORIZE, 0, 0, 0, 127 * ((100 - $pct) / 100));
}
imagecopy($dstIm, $srcIm, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH);
imagecopy($dstIm, $srcIm, (int) $dstX, (int) $dstY, (int) $srcX, (int) $srcY, (int) $srcW, (int) $srcH);
return true;
}
@ -593,7 +632,7 @@ class SimpleImage {
// Avoid using native imagecrop() because of a bug with PNG transparency
$dstW = abs($x2 - $x1);
$dstH = abs($y2 - $y1);
$newImage = imagecreatetruecolor($dstW, $dstH);
$newImage = imagecreatetruecolor((int) $dstW, (int) $dstH);
$transparentColor = imagecolorallocatealpha($newImage, 0, 0, 0, 127);
imagecolortransparent($newImage, $transparentColor);
imagefill($newImage, 0, 0, $transparentColor);
@ -603,10 +642,10 @@ class SimpleImage {
$newImage,
$this->image,
0, 0, min($x1, $x2), min($y1, $y2),
$dstW,
$dstH,
$dstW,
$dstH
(int) $dstW,
(int) $dstH,
(int) $dstW,
(int) $dstH
);
// Swap out the new image
@ -802,7 +841,7 @@ class SimpleImage {
// We can't use imagescale because it doesn't seem to preserve transparency properly. The
// workaround is to create a new truecolor image, allocate a transparent color, and copy the
// image over to it using imagecopyresampled.
$newImage = imagecreatetruecolor($width, $height);
$newImage = imagecreatetruecolor((int) $width, (int) $height);
$transparentColor = imagecolorallocatealpha($newImage, 0, 0, 0, 127);
imagecolortransparent($newImage, $transparentColor);
imagefill($newImage, 0, 0, $transparentColor);
@ -810,8 +849,8 @@ class SimpleImage {
$newImage,
$this->image,
0, 0, 0, 0,
$width,
$height,
(int) $width,
(int) $height,
$this->getWidth(),
$this->getHeight()
);
@ -1885,7 +1924,7 @@ class SimpleImage {
$color['red'],
$color['green'],
$color['blue'],
127 - ($color['alpha'] * 127)
(int) (127 - ($color['alpha'] * 127))
);
if($index > -1) {
// Yes, return this color index

View file

@ -0,0 +1,13 @@
{
"plugin-data":
{
"name": "Twitter Cards",
"description": "With Twitter Cards, you can attach rich photos, videos and media experiences to Tweets, helping to drive traffic to your website."
},
"default-image": "Výchozí obrázek",
"twitter-site-profile": "Profil stránky na Twitteru",
"twitter-author-profile": "Profil autora příspěvku na Twitteru",
"minimum-image-dimensions": "Minimální rozměry obrázku jsou 300x157px a maximum 4096x4096px.",
"image-must-be-less": "Obrázek musí být menší než 5MB.",
"formats-are-supported": "Jsou podporovány formáty pouze JPG, PNG, WEBP a GIF."
}

View file

@ -4,5 +4,10 @@
"name": "Twitter Cards",
"description": "With Twitter Cards, you can attach rich photos, videos and media experiences to Tweets, helping to drive traffic to your website."
},
"default-image": "Default image"
}
"default-image": "Default image",
"twitter-site-profile": "Twitter site profile",
"twitter-author-profile": "Twitter author profile",
"minimum-image-dimensions": "The minimum image dimensions are 300x157px and the maximum 4096x4096px.",
"image-must-be-less": "Image must be less than 5MB in size.",
"formats-are-supported": "JPG, PNG, WEBP and GIF formats are supported."
}

View file

@ -3,8 +3,8 @@
"email": "",
"website": "https://plugins.bludit.com",
"version": "4.0.0",
"releaseDate": "2021-05-23",
"releaseDate": "2022-10-01",
"license": "MIT",
"compatible": "4.0.0",
"notes": ""
}
}

View file

@ -6,7 +6,9 @@ class pluginTwitterCards extends Plugin {
{
// Fields and default values for the database of this plugin
$this->dbFields = array(
'defaultImage'=>''
'defaultImage' => '',
'twitterSite' => '',
'twitterCreator' => ''
);
}
@ -14,9 +16,24 @@ class pluginTwitterCards extends Plugin {
{
global $L;
$html = '<div>';
$html = '<div class="alert alert-primary" role="alert">';
$html .= $this->description();
$html .= '</div>';
$html .= '<div>';
$html .= '<label>'.$L->get('Default image').'</label>';
$html .= '<input id="jsdefaultImage" name="defaultImage" type="text" value="'.$this->getValue('defaultImage').'" placeholder="https://">';
$html .= '<p class="text-muted small">' . $L->get('minimum-image-dimensions') . ' ' . $L->get('image-must-be-less') . ' ' . $L->get('formats-are-supported') . '</p>';
$html .= '</div>';
$html .= '<div>';
$html .= '<label>'.$L->get('Twitter site profile').'</label>';
$html .= '<input id="jstwitterSite" name="twitterSite" type="text" value="'.$this->getValue('twitterSite').'" placeholder="@yourSiteProfile">';
$html .= '</div>';
$html .= '<div>';
$html .= '<label>'.$L->get('Twitter author profile').'</label>';
$html .= '<input id="jstwitterCreator" name="twitterCreator" type="text" value="'.$this->getValue('twitterCreator').'" placeholder="@authorProfile">';
$html .= '</div>';
return $html;
@ -31,19 +48,20 @@ class pluginTwitterCards extends Plugin {
global $page;
$data = array(
'card' =>'summary',
'site' =>'',
'title' =>$site->title(),
'description' =>$site->description(),
'image' =>''
'card' => 'summary_large_image',
'twitterSite' => $this->getValue('twitterSite'),
'twitterCreator' => $this->getValue('twitterCreator'),
'title' => $site->title(),
'description' => $site->description(),
'image' => ''
);
switch($WHERE_AM_I) {
switch( $WHERE_AM_I ) {
// The user filter by page
case 'page':
$data['title'] = $page->title();
$data['description'] = $page->description();
$data['image'] = $page->coverImage($absolute=true);
$data['title'] = $page->title();
$data['description'] = $page->description();
$data['image'] = $page->coverImage( $absolute = true );
$pageContent = $page->content();
break;
@ -53,32 +71,75 @@ class pluginTwitterCards extends Plugin {
$pageContent = '';
// The image it's from the first page
if(isset($content[0]) ) {
$data['image'] = $content[0]->coverImage($absolute=true);
$data['image'] = $content[0]->coverImage( $absolute = true );
$pageContent = $content[0]->content();
}
break;
}
$html = PHP_EOL.'<!-- Twitter Cards -->'.PHP_EOL;
$html .= '<meta property="twitter:card" content="'.$data['card'].'">'.PHP_EOL;
$html .= '<meta property="twitter:site" content="'.$data['site'].'">'.PHP_EOL;
$html .= '<meta property="twitter:title" content="'.$data['title'].'">'.PHP_EOL;
$html .= '<meta property="twitter:description" content="'.$data['description'].'">'.PHP_EOL;
$html .= '<meta name="twitter:card" content="' . $data['card'] . '">'.PHP_EOL;
$html .= '<meta name="twitter:site" content="' . $data['site'] . '">'.PHP_EOL;
$html .= '<meta name="twitter:title" content="' . $data['title'] . '">'.PHP_EOL;
$html .= '<meta name="twitter:creator" content="' . $data['twitterCreator'] . '">'.PHP_EOL;
// If the page doesn't have a description try to get excerpt from content
if( empty( $data['description'] ) )
{
$data['description'] = $this->content_excerpt( $pageContent , 150, '...');
}
$html .= '<meta name="twitter:description" content="' . $data['description'] . '">'.PHP_EOL;
// If the page doesn't have a coverImage try to get an image from the HTML content
if( empty($data['image']) ) {
if( empty( $data['image'] ) ) {
// Get the image from the content
$src = DOM::getFirstImage($pageContent);
if ($src!==false) {
$src = DOM::getFirstImage( $pageContent );
if ( $src !== false ) {
$data['image'] = $src;
} else {
if (Text::isNotEmpty($this->getValue('defaultImage'))) {
if ( Text::isNotEmpty( $this->getValue('defaultImage') ) ) {
$data['image'] = $this->getValue('defaultImage');
}
}
}
$html .= '<meta property="twitter:image" content="'.$data['image'].'">'.PHP_EOL;
$html .= '<meta name="twitter:image" content="'.$data['image'].'">'.PHP_EOL;
$html .= '<!-- /Twitter Cards -->'.PHP_EOL.PHP_EOL;
unset( $pageContent );
unset( $data );
return $html;
}
}
/** Return excerpt from full content of post
*
* @param string $str Post content
* @param int $n Number of characters
* @param string $endChar End char append to after excerpt (default "...")
* @return string
*/
private function content_excerpt( string $str, int $n = 500, string $endChar = '&#8230;' ): string
{
$str = strip_tags( $str );
if ( mb_strlen( $str ) < $n )
{
return $str;
}
$str = preg_replace('/ {2,}/', ' ', str_replace(["\r", "\n", "\t", "\x0B", "\x0C"], ' ', $str));
if ( mb_strlen( $str ) <= $n )
{
return $str;
}
$out = '';
foreach ( explode( ' ', trim( $str ) ) as $val )
{
$out .= $val . ' ';
if ( mb_strlen( $out ) >= $n )
{
$out = trim( $out );
break;
}
}
return ( mb_strlen( $out ) === mb_strlen( $str ) ) ? $out : $out . $endChar;
}
}

View file

@ -724,7 +724,7 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
<table class="table">
<tbody>
<tr>
<th>' . $error . '</th>
<th>' . $L->get( $error ) . '</th>
</tr>
</tbody>
</table>