phpWord convert using imagick on element/image class - php

I would like to find a way to use image magick in the following class to convert the source to jpg (the code come from phpWord library):
<?php
/**
* This file is part of PHPWord - A pure PHP library for reading and writing
* word processing documents.
*
* PHPWord is free software distributed under the terms of the GNU Lesser
* General Public License version 3 as published by the Free Software Foundation.
*
* For the full copyright and license information, please read the LICENSE
* file that was distributed with this source code. For the full list of
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
*
* #see https://github.com/PHPOffice/PHPWord
* #copyright 2010-2018 PHPWord contributors
* #license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
namespace PhpOffice\PhpWord\Element;
use PhpOffice\PhpWord\Exception\CreateTemporaryFileException;
use PhpOffice\PhpWord\Exception\InvalidImageException;
use PhpOffice\PhpWord\Exception\UnsupportedImageTypeException;
use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\Shared\ZipArchive;
use PhpOffice\PhpWord\Style\Image as ImageStyle;
/**
* Image element
*/
class Image extends AbstractElement
{
/**
* Image source type constants
*/
const SOURCE_LOCAL = 'local'; // Local images
const SOURCE_GD = 'gd'; // Generated using GD
const SOURCE_ARCHIVE = 'archive'; // Image in archives zip://$archive#$image
const SOURCE_STRING = 'string'; // Image from string
/**
* Image source
*
* #var string
*/
private $source;
/**
* Source type: local|gd|archive
*
* #var string
*/
private $sourceType;
/**
* Image style
*
* #var ImageStyle
*/
private $style;
/**
* Is watermark
*
* #var bool
*/
private $watermark;
/**
* Name of image
*
* #var string
*/
private $name;
/**
* Image type
*
* #var string
*/
private $imageType;
/**
* Image create function
*
* #var string
*/
private $imageCreateFunc;
/**
* Image function
*
* #var string
*/
private $imageFunc;
/**
* Image extension
*
* #var string
*/
private $imageExtension;
/**
* Is memory image
*
* #var bool
*/
private $memoryImage;
/**
* Image target file name
*
* #var string
*/
private $target;
/**
* Image media index
*
* #var int
*/
private $mediaIndex;
/**
* Has media relation flag; true for Link, Image, and Object
*
* #var bool
*/
protected $mediaRelation = true;
/**
* Create new image element
*
* #param string $source
* #param mixed $style
* #param bool $watermark
* #param string $name
*
* #throws \PhpOffice\PhpWord\Exception\InvalidImageException
* #throws \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException
*/
public function __construct($source, $style = null, $watermark = false, $name = null)
{
$this->source = $source;
$this->style = $this->setNewStyle(new ImageStyle(), $style, true);
$this->setIsWatermark($watermark);
$this->setName($name);
$this->checkImage();
}
/**
* Get Image style
*
* #return ImageStyle
*/
public function getStyle()
{
return $this->style;
}
/**
* Get image source
*
* #return string
*/
public function getSource()
{
return $this->source;
}
/**
* Get image source type
*
* #return string
*/
public function getSourceType()
{
return $this->sourceType;
}
/**
* Sets the image name
*
* #param string $value
*/
public function setName($value)
{
$this->name = $value;
}
/**
* Get image name
*
* #return null|string
*/
public function getName()
{
return $this->name;
}
/**
* Get image media ID
*
* #return string
*/
public function getMediaId()
{
return md5($this->source);
}
/**
* Get is watermark
*
* #return bool
*/
public function isWatermark()
{
return $this->watermark;
}
/**
* Set is watermark
*
* #param bool $value
*/
public function setIsWatermark($value)
{
$this->watermark = $value;
}
/**
* Get image type
*
* #return string
*/
public function getImageType()
{
return $this->imageType;
}
/**
* Get image create function
*
* #return string
*/
public function getImageCreateFunction()
{
return $this->imageCreateFunc;
}
/**
* Get image function
*
* #return string
*/
public function getImageFunction()
{
return $this->imageFunc;
}
/**
* Get image extension
*
* #return string
*/
public function getImageExtension()
{
return $this->imageExtension;
}
/**
* Get is memory image
*
* #return bool
*/
public function isMemImage()
{
return $this->memoryImage;
}
/**
* Get target file name
*
* #return string
*/
public function getTarget()
{
return $this->target;
}
/**
* Set target file name.
*
* #param string $value
*/
public function setTarget($value)
{
$this->target = $value;
}
/**
* Get media index
*
* #return int
*/
public function getMediaIndex()
{
return $this->mediaIndex;
}
/**
* Set media index.
*
* #param int $value
*/
public function setMediaIndex($value)
{
$this->mediaIndex = $value;
}
/**
* Get image string data
*
* #param bool $base64
* #return string|null
* #since 0.11.0
*/
public function getImageStringData($base64 = false)
{
$source = $this->source;
$actualSource = null;
$imageBinary = null;
$imageData = null;
$isTemp = false;
// Get actual source from archive image or other source
// Return null if not found
if ($this->sourceType == self::SOURCE_ARCHIVE) {
$source = substr($source, 6);
list($zipFilename, $imageFilename) = explode('#', $source);
$zip = new ZipArchive();
if ($zip->open($zipFilename) !== false) {
if ($zip->locateName($imageFilename) !== false) {
$isTemp = true;
$zip->extractTo(Settings::getTempDir(), $imageFilename);
$actualSource = Settings::getTempDir() . DIRECTORY_SEPARATOR . $imageFilename;
}
}
$zip->close();
} else {
$actualSource = $source;
}
// Can't find any case where $actualSource = null hasn't captured by
// preceding exceptions. Please uncomment when you find the case and
// put the case into Element\ImageTest.
// if ($actualSource === null) {
// return null;
// }
// Read image binary data and convert to hex/base64 string
if ($this->sourceType == self::SOURCE_GD) {
$imageResource = call_user_func($this->imageCreateFunc, $actualSource);
if ($this->imageType === 'image/png') {
// PNG images need to preserve alpha channel information
imagesavealpha($imageResource, true);
}
ob_start();
call_user_func($this->imageFunc, $imageResource);
$imageBinary = ob_get_contents();
ob_end_clean();
} elseif ($this->sourceType == self::SOURCE_STRING) {
$imageBinary = $this->source;
} else {
$fileHandle = fopen($actualSource, 'rb', false);
if ($fileHandle !== false) {
$imageBinary = fread($fileHandle, filesize($actualSource));
fclose($fileHandle);
}
}
if ($imageBinary !== null) {
if ($base64) {
$imageData = chunk_split(base64_encode($imageBinary));
} else {
$imageData = chunk_split(bin2hex($imageBinary));
}
}
// Delete temporary file if necessary
if ($isTemp === true) {
#unlink($actualSource);
}
return $imageData;
}
/**
* Check memory image, supported type, image functions, and proportional width/height.
*
* #throws \PhpOffice\PhpWord\Exception\InvalidImageException
* #throws \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException
*/
private function checkImage()
{
$this->setSourceType();
// Check image data
if ($this->sourceType == self::SOURCE_ARCHIVE) {
$imageData = $this->getArchiveImageSize($this->source);
} elseif ($this->sourceType == self::SOURCE_STRING) {
$imageData = $this->getStringImageSize($this->source);
} else {
$imageData = #getimagesize($this->source);
}
if (!is_array($imageData)) {
throw new InvalidImageException(sprintf('Invalid image: %s', $this->source));
}
list($actualWidth, $actualHeight, $imageType) = $imageData;
// Check image type support
$supportedTypes = array(IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_PNG);
if ($this->sourceType != self::SOURCE_GD && $this->sourceType != self::SOURCE_STRING) {
$supportedTypes = array_merge($supportedTypes, array(IMAGETYPE_BMP, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM));
}
if (!in_array($imageType, $supportedTypes)) {
throw new UnsupportedImageTypeException();
}
// Define image functions
$this->imageType = image_type_to_mime_type($imageType);
$this->setFunctions();
$this->setProportionalSize($actualWidth, $actualHeight);
}
/**
* Set source type.
*/
private function setSourceType()
{
if (stripos(strrev($this->source), strrev('.php')) === 0) {
$this->memoryImage = true;
$this->sourceType = self::SOURCE_GD;
} elseif (strpos($this->source, 'zip://') !== false) {
$this->memoryImage = false;
$this->sourceType = self::SOURCE_ARCHIVE;
} elseif (filter_var($this->source, FILTER_VALIDATE_URL) !== false) {
$this->memoryImage = true;
if (strpos($this->source, 'https') === 0) {
$fileContent = file_get_contents($this->source);
$this->source = $fileContent;
$this->sourceType = self::SOURCE_STRING;
} else {
$this->sourceType = self::SOURCE_GD;
}
} elseif ((strpos($this->source, chr(0)) === false) && #file_exists($this->source)) {
$this->memoryImage = false;
$this->sourceType = self::SOURCE_LOCAL;
} else {
$this->memoryImage = true;
$this->sourceType = self::SOURCE_STRING;
}
}
/**
* Get image size from archive
*
* #since 0.12.0 Throws CreateTemporaryFileException.
*
* #param string $source
*
* #throws \PhpOffice\PhpWord\Exception\CreateTemporaryFileException
*
* #return array|null
*/
private function getArchiveImageSize($source)
{
$imageData = null;
$source = substr($source, 6);
list($zipFilename, $imageFilename) = explode('#', $source);
$tempFilename = tempnam(Settings::getTempDir(), 'PHPWordImage');
if (false === $tempFilename) {
throw new CreateTemporaryFileException(); // #codeCoverageIgnore
}
$zip = new ZipArchive();
if ($zip->open($zipFilename) !== false) {
if ($zip->locateName($imageFilename) !== false) {
$imageContent = $zip->getFromName($imageFilename);
if ($imageContent !== false) {
file_put_contents($tempFilename, $imageContent);
$imageData = getimagesize($tempFilename);
unlink($tempFilename);
}
}
$zip->close();
}
return $imageData;
}
/**
* get image size from string
*
* #param string $source
*
* #codeCoverageIgnore this method is just a replacement for getimagesizefromstring which exists only as of PHP 5.4
*/
private function getStringImageSize($source)
{
$result = false;
if (!function_exists('getimagesizefromstring')) {
$uri = 'data://application/octet-stream;base64,' . base64_encode($source);
$result = #getimagesize($uri);
} else {
$result = #getimagesizefromstring($source);
}
return $result;
}
/**
* Set image functions and extensions.
*/
private function setFunctions()
{
switch ($this->imageType) {
case 'image/png':
$this->imageCreateFunc = $this->sourceType == self::SOURCE_STRING ? 'imagecreatefromstring' : 'imagecreatefrompng';
$this->imageFunc = 'imagepng';
$this->imageExtension = 'png';
break;
case 'image/gif':
$this->imageCreateFunc = $this->sourceType == self::SOURCE_STRING ? 'imagecreatefromstring' : 'imagecreatefromgif';
$this->imageFunc = 'imagegif';
$this->imageExtension = 'gif';
break;
case 'image/jpeg':
case 'image/jpg':
$this->imageCreateFunc = $this->sourceType == self::SOURCE_STRING ? 'imagecreatefromstring' : 'imagecreatefromjpeg';
$this->imageFunc = 'imagejpeg';
$this->imageExtension = 'jpg';
break;
case 'image/bmp':
case 'image/x-ms-bmp':
$this->imageType = 'image/bmp';
$this->imageExtension = 'bmp';
break;
case 'image/tiff':
$this->imageExtension = 'tif';
break;
}
}
/**
* Set proportional width/height if one dimension not available.
*
* #param int $actualWidth
* #param int $actualHeight
*/
private function setProportionalSize($actualWidth, $actualHeight)
{
$styleWidth = $this->style->getWidth();
$styleHeight = $this->style->getHeight();
if (!($styleWidth && $styleHeight)) {
if ($styleWidth == null && $styleHeight == null) {
$this->style->setWidth($actualWidth);
$this->style->setHeight($actualHeight);
} elseif ($styleWidth) {
$this->style->setHeight($actualHeight * ($styleWidth / $actualWidth));
} else {
$this->style->setWidth($actualWidth * ($styleHeight / $actualHeight));
}
}
}
/**
* Get is watermark
*
* #deprecated 0.10.0
*
* #codeCoverageIgnore
*/
public function getIsWatermark()
{
return $this->isWatermark();
}
/**
* Get is memory image
*
* #deprecated 0.10.0
*
* #codeCoverageIgnore
*/
public function getIsMemImage()
{
return $this->isMemImage();
}
}
As you can see from the private function checkImage(), the image source must be jpg, gif on png. Sometimes the format of the image is different. So I want to convert it first to jpg.
But I dont know where to implement the following:
$image =$source;
$img = new Imagick($image);
$img->setImageFormat('jpeg');
I tried to put it within the class as follow but I don't think thats how a class works:
public function __construct($source, $style = null, $watermark = false, $name = null)
{
$image =$source;
$img = new Imagick($image);
$img->setImageFormat('jpeg');
$this->source = $img;
$this->style = $this->setNewStyle(new ImageStyle(), $style, true);
$this->setIsWatermark($watermark);
$this->setName($name);
$this->checkImage();
}
I got the error:
Fatal error: Uncaught Error: Class "PhpOffice\PhpWord\Element\Imagick" not found in /var/www/websource/libraries/vendor/phpoffice/phpword/src/PhpWord/Element/Image.php:145 Stack trace: #0
FYI imagick is installed and work properly when i want to convert an img.
Thank you

Related

How to disable _PHCR key pefixes used in Phalcon Redis backend

I'm using Phalcon Redis backend to store some data. I later try to access this data in Lua language embedded into nginx. What drives me crazy is that Phalcon adds some garbage prefixes to Redis keys and some terrible prefixes to values. So, if I store this pair in Redis - (abc, querty) - this is what is really stored:
(_PHCRabc, s:6:"querty")
Is it possible to disable all this garbage and continue working with Phalcon Redis backend?
According to the the source it is not possible to disable it with option: https://github.com/phalcon/cphalcon/blob/master/phalcon/cache/backend/redis.zep
public function get(string keyName, int lifetime = null) -> var | null
let lastKey = "_PHCR" . prefix . keyName;
public function save(keyName = null, content = null, lifetime = null, boolean stopBuffer = true) -> boolean
lastKey = "_PHCR" . prefixedKey,
Also quoting the docs:
This adapter uses the special redis key “_PHCR” to store all the keys
internally used by the adapter
I read somewhere that this is done in order to be able to flush Phalcon generated cache files.
Your best option would be to extend the \Phalcon\Cache\Backend\Redis class and overwrite the save/get methods. And after use your class in the service:
// Cache
$di->setShared('cache', function() use ($config) {
return new MyCustomRedis(
new \Phalcon\Cache\Frontend\Json(['lifetime' => 172800]), // 2d
$config->redis
);
});
You can override the redis adapter like this.
<?php
namespace App\Library\Cache\Backend;
use Phalcon\Cache\Exception;
class Redis extends \Phalcon\Cache\Backend\Redis
{
/**
* #var \Redis
*/
protected $_redis;
/**
* {#inheritdoc}
*
* #param string $keyName
* #param integer $lifetime
* #return mixed|null
*/
public function get($keyName, $lifetime = null)
{
$redis = $this->getRedis();
/**
* #var \Phalcon\Cache\FrontendInterface $frontend
*/
$frontend = $this->_frontend;
$lastKey = $this->getKeyName($keyName);
$this->_lastKey = $lastKey;
$content = $redis->get($lastKey);
if ($content === false) {
return null;
}
if (is_numeric($content)) {
return $content;
}
return $frontend->afterRetrieve($content);
}
/**
* {#inheritdoc}
*
* #param string $keyName
* #param string $content
* #param int $lifetime
* #param bool $stopBuffer
* #return bool
*
* #throws Exception
*/
public function save($keyName = null, $content = null, $lifetime = null, $stopBuffer = true)
{
if ($keyName === null) {
$lastKey = $this->_lastKey;
} else {
$lastKey = $this->getKeyName($keyName);
$this->_lastKey = $lastKey;
}
if (!$lastKey) {
throw new Exception('The cache must be started first');
}
$redis = $this->getRedis();
/**
* #var \Phalcon\Cache\FrontendInterface $frontend
*/
$frontend = $this->_frontend;
if ($content === null) {
$cachedContent = $frontend->getContent();
} else {
$cachedContent = $content;
}
/**
* Prepare the content in the frontend
*/
if (!is_numeric($cachedContent)) {
$preparedContent = $frontend->beforeStore($cachedContent);
} else {
$preparedContent = $cachedContent;
}
if ($lifetime === null) {
$tmp = $this->_lastLifetime;
$ttl = $tmp ? $tmp : $frontend->getLifetime();
} else {
$ttl = $lifetime;
}
$success = $redis->set($lastKey, $preparedContent);
if (!$success) {
throw new Exception('Failed storing the data in redis');
}
if ($ttl > 0) {
$redis->setTimeout($lastKey, $ttl);
}
$isBuffering = $frontend->isBuffering();
if ($stopBuffer === true) {
$frontend->stop();
}
if ($isBuffering === true) {
echo $cachedContent;
}
$this->_started = false;
return $success;
}
/**
* {#inheritdoc}
*
* #param string $keyName
* #return bool
*/
public function delete($keyName)
{
$redis = $this->getRedis();
$lastKey = $this->getKeyName($keyName);
return (bool)$redis->delete($lastKey);
}
/**
* {#inheritdoc}
*
* #param string $prefix
* #return array
*/
public function queryKeys($prefix = null)
{
$redis = $this->getRedis();
$pattern = "{$this->_prefix}" . ($prefix ? $prefix : '') . '*';
return $redis->keys($pattern);
}
/**
* {#inheritdoc}
*
* #param string $keyName
* #param string $lifetime
* #return bool
*/
public function exists($keyName = null, $lifetime = null)
{
$redis = $this->getRedis();
if ($keyName === null) {
$lastKey = $this->_lastKey;
} else {
$lastKey = $this->getKeyName($keyName);
}
return (bool)$redis->exists($lastKey);
}
/**
* {#inheritdoc}
*
* #param string $keyName
* #param int $value
* #return int
*/
public function increment($keyName = null, $value = 1)
{
$redis = $this->getRedis();
if ($keyName === null) {
$lastKey = $this->_lastKey;
} else {
$lastKey = $this->getKeyName($keyName);
}
return $redis->incrBy($lastKey, $value);
}
/**
* {#inheritdoc}
*
* #param string $keyName
* #param int $value
* #return int
*/
public function decrement($keyName = null, $value = 1)
{
$redis = $this->getRedis();
if ($keyName === null) {
$lastKey = $this->_lastKey;
} else {
$lastKey = $this->getKeyName($keyName);
}
return $redis->decrBy($lastKey, $value);
}
/**
* {#inheritdoc}
*
* #return bool
*/
public function flush()
{
}
/**
* Get Prefix
*
* #return string
*/
public function getPrefix()
{
return $this->_prefix;
}
/**
* Get Redis Connection
*
* #return \Redis
*/
public function getRedis()
{
$redis = $this->_redis;
if (!is_object($redis)) {
$this->_connect();
$redis = $this->_redis;
}
return $redis;
}
/**
* Get Key Name
*
* #param $keyName
* #return string
*/
protected function getKeyName($keyName)
{
return $this->_prefix . $keyName;
}
}

Setting EXIF data using PHP

I'm trying to overwrite/save JPEG file's EXIF data using https://github.com/lsolesen/pel library. Here is the code that has to save new EXIF data:
use lsolesen\pel\PelJpeg;
use lsolesen\pel\PelTag;
use lsolesen\pel\PelEntryAscii;
...
$pelJpeg = new PelJpeg(Yii::getAlias('#str-set') . "/$this->hash.jpg");
$pelExif = $pelJpeg->getExif();
if ($pelExif == null) {
$pelExif = new PelExif();
$pelJpeg->setExif($pelExif);
}
$pelTiff = $pelExif->getTiff();
if ($pelTiff == null) {
$pelTiff = new PelTiff();
$pelExif->setTiff($pelTiff);
}
$pelIfd0 = $pelTiff->getIfd();
if ($pelIfd0 == null) {
$pelIfd0 = new PelIfd(PelIfd::IFD0);
$pelTiff->setIfd($pelIfd0);
}
$pelIfd0->addEntry(new PelEntryAscii(
PelTag::IMAGE_DESCRIPTION, $this->description
)
);
$pelIfd0->addEntry(new PelEntryAscii(
PelTag::XP_TITLE, $this->title
)
);
$keywords = [];
foreach ($this->keywords as $keyword)
$keywords[] = $keyword->title;
$kw_string = implode(", ", $keywords);
$pelIfd0->addEntry(new PelEntryAscii(
PelTag::XP_KEYWORDS, $kw_string
)
);
$pelJpeg->saveFile(Yii::getAlias('#str-set') . "/$this->hash.jpg");
...
Here is the photo for testing
Here is sample tags:
icon, vector, background
But I'm getting the file without any tags, description or title saved.
So the result has to be like this:
But getting this
What am I doing wrong?
Here is a stand-alone class to write EXIF data, extracted from the library Image_Iptc (original class by Bruno Agutoli).
<?php
class IPTC
{
const OBJECT_NAME = '005';
const EDIT_STATUS = '007';
const PRIORITY = '010';
const CATEGORY = '015';
const SUPPLEMENTAL_CATEGORY = '020';
const FIXTURE_IDENTIFIER = '022';
const KEYWORDS = '025';
const RELEASE_DATE = '030';
const RELEASE_TIME = '035';
const SPECIAL_INSTRUCTIONS = '040';
const REFERENCE_SERVICE = '045';
const REFERENCE_DATE = '047';
const REFERENCE_NUMBER = '050';
const CREATED_DATE = '055';
const CREATED_TIME = '060';
const ORIGINATING_PROGRAM = '065';
const PROGRAM_VERSION = '070';
const OBJECT_CYCLE = '075';
const BYLINE = '080';
const BYLINE_TITLE = '085';
const CITY = '090';
const PROVINCE_STATE = '095';
const COUNTRY_CODE = '100';
const COUNTRY = '101';
const ORIGINAL_TRANSMISSION_REFERENCE = '103';
const HEADLINE = '105';
const CREDIT = '110';
const SOURCE = '115';
const COPYRIGHT_STRING = '116';
const CAPTION = '120';
const LOCAL_CAPTION = '121';
const CAPTION_WRITER = '122';
/**
* variable that stores the IPTC tags
*
* #var array
*/
private $_meta = array();
/**
* This variable was checks whether any tag class setada
*
* #var boolean
*/
private $_hasMeta = false;
/**
* allowed extensions
*
* #var array
*/
private $_allowedExt = array('jpg', 'jpeg', 'pjpeg');
/**
* Image name ex. /home/user/image.jpg
*
* #var String
*/
private $_filename;
/**
* Constructor class
*
* #param string $filename - Name of file
*
* #see http://php.net/manual/en/book.image.php - PHP GD
* #see iptcparse
* #see getimagesize
* #throws Exception
*/
public function __construct($filename)
{
/**
* Check PHP version
* #since 2.0.1
*/
if (version_compare(phpversion(), '5.1.3', '<') === true) {
throw new Exception(
'ERROR: Your PHP version is ' . phpversion() .
'. Iptc class requires PHP 5.1.3 or newer.'
);
}
if (!extension_loaded('gd')) {
throw new Exception(
'Since PHP 4.3 there is a bundled version of the GD lib.'
);
}
if (!file_exists($filename)) {
throw new Exception(
'Image not found!'
);
}
if (!is_writable($filename)) {
throw new Exception(
"File \"{$filename}\" is not writable!"
);
}
$parts = explode('.', strtolower($filename));
if (!in_array(end($parts), $this->_allowedExt)) {
throw new Exception(
'Support only for the following extensions: ' .
implode(',', $this->_allowedExt)
);
}
$size = getimagesize($filename, $imageinfo);
if (empty($size['mime']) || $size['mime'] != 'image/jpeg') {
throw new Exception(
'Support only JPEG images'
);
}
$this->_hasMeta = isset($imageinfo["APP13"]);
if ($this->_hasMeta) {
$this->_meta = iptcparse($imageinfo["APP13"]);
}
$this->_filename = $filename;
}
/**
* Set parameters you want to record in a particular tag "IPTC"
*
* #param Integer|const $tag - Code or const of tag
* #param array|mixed $data - Value of tag
*
* #return Iptc object
* #access public
*/
public function set($tag, $data)
{
$data = $this->_charset_decode($data);
$this->_meta["2#{$tag}"] = array($data);
$this->_hasMeta = true;
return $this;
}
/**
* adds an item at the beginning of the array
*
* #param Integer|const $tag - Code or const of tag
* #param array|mixed $data - Value of tag
*
* #return Iptc object
* #access public
*/
public function prepend($tag, $data)
{
$data = $this->_charset_decode($data);
if (!empty($this->_meta["2#{$tag}"])) {
array_unshift($this->_meta["2#{$tag}"], $data);
$data = $this->_meta["2#{$tag}"];
}
$this->_meta["2#{$tag}"] = array($data);
$this->_hasMeta = true;
return $this;
}
/**
* adds an item at the end of the array
*
* #param Integer|const $tag - Code or const of tag
* #param array|mixed $data - Value of tag
*
* #return Iptc object
* #access public
*/
public function append($tag, $data)
{
$data = $this->_charset_decode($data);
if (!empty($this->_meta["2#{$tag}"])) {
array_push($this->_meta["2#{$tag}"], $data);
$data = $this->_meta["2#{$tag}"];
}
$this->_meta["2#{$tag}"] = array($data);
$this->_hasMeta = true;
return $this;
}
/**
* Return fisrt IPTC tag by tag name
*
* #param Integer|const $tag - Name of tag
*
* #example $iptc->fetch(Iptc::KEYWORDS);
*
* #access public
* #return mixed|false
*/
public function fetch($tag)
{
if (isset($this->_meta["2#{$tag}"])) {
return $this->_charset_encode($this->_meta["2#{$tag}"][0]);
}
return false;
}
/**
* Return all IPTC tags by tag name
*
* #param Integer|const $tag - Name of tag
*
* #example $iptc->fetchAll(Iptc::KEYWORDS);
*
* #access public
* #return mixed|false
*/
public function fetchAll($tag)
{
if (isset($this->_meta["2#{$tag}"])) {
return $this->_charset_encode($this->_meta["2#{$tag}"]);
}
return false;
}
/**
* debug that returns all the IPTC tags already in the image
*
* #access public
* #return string
*/
public function dump()
{
return $this->_charset_encode(print_r($this->_meta, true));
}
/**
* returns a string with the binary code
*
* #access public
* #return string
*/
public function binary()
{
$iptc = '';
foreach (array_keys($this->_meta) as $key) {
$tag = str_replace("2#", "", $key);
foreach ($this->_meta[$key] as $value) {
$iptc .= $this->iptcMakeTag(2, $tag, $value);
}
}
return $iptc;
}
/**
* Assemble the tags "IPTC" in character "ascii"
*
* #param Integer $rec - Type of tag ex. 2
* #param Integer $dat - code of tag ex. 025 or 000 etc
* #param mixed $val - any character
*
* #access public
* #return string binary source
*/
public function iptcMakeTag($rec, $dat, $val)
{
//beginning of the binary string
$iptcTag = chr(0x1c) . chr($rec) . chr($dat);
if (is_array($val)) {
$src = '';
foreach ($val as $item) {
$len = strlen($item);
$src .= $iptcTag . $this->_testBitSize($len) . $item;
}
return $src;
}
$len = strlen($val);
$src = $iptcTag . $this->_testBitSize($len) . $val;
return $src;
}
/**
* create the new image file already
* with the new "IPTC" recorded
*
* #access public
* #return string binary source
* #throws Exception
*/
public function write()
{
//#see http://php.net/manual/en/function.iptcembed.php
$content = iptcembed($this->binary(), $this->_filename, 0);
if ($content === false) {
throw new Exception(
'Failed to save IPTC data into file'
);
}
unlink($this->_filename);
if ($file = fopen($this->_filename, "w")) {
fwrite($file, $content);
//fwrite($file, pack("CCC",0xef,0xbb,0xbf));
fclose($file);
return true;
}
return false;
}
/**
* completely remove all tags "IPTC" image
*
* #access public
* #return string binary source
*/
public function removeAllTags()
{
$this->_hasMeta = false;
$this->_meta = Array();
$impl = implode(file($this->_filename));
$img = imagecreatefromstring($impl);
unlink($this->_filename);
imagejpeg($img, $this->_filename, 100);
}
/**
* It proper test to ensure that
* the size of the values are supported within the
*
* #param Integer $len - size of the character
*
* #access public
* #return string binary source
*/
private function _testBitSize($len)
{
if ($len < 0x8000) {
return
chr($len >> 8) .
chr($len & 0xff);
}
return
chr(0x1c) . chr(0x04) .
chr(($len >> 24) & 0xff) .
chr(($len >> 16) & 0xff) .
chr(($len >> 8) & 0xff) .
chr(($len) & 0xff);
}
/**
* Decode charset utf8 before being saved
*
* #param String $data
* #access private
* #return string decoded string
*/
private function _charset_decode($data)
{
$result = array();
if (is_array($data)) {
$iterator = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($data));
foreach ($iterator as $key => $value) {
$result[] = utf8_decode($value);
}
} else {
return utf8_decode($data);
}
return $result;
}
/**
* Encode charset to utf8 before being saved
*
* #param String $data
* #access private
* #return string encoded string
*/
private function _charset_encode($data)
{
$result = array();
if (is_array($data)) {
$iterator = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($data));
foreach ($iterator as $key => $value) {
$result[] = utf8_encode($value);
}
} else {
return utf8_encode($data);
}
return $result;
}
}
Most of these field belongs to IPTC block.
I recommend You to use iptc-jpeg package to comfortably update these fields.

How to transfer files from another server, using FTP, in PHP

I am trying to find a way to transfer files from server-to-server. The source server can be any platform, and we may not even really know anything about it except that it supports FTP.
A number of posts I have found on SO recommend using scp, sftp, rsync, or wget for this purpose. Given that this PHP script needs to work every time, and the only thing we know for sure is that the source server supports FTP, how can this be achieved?
I found a couple FTP examples on SO, but they weren't explained very well.
We need to be able to download all files and folders, keeping the same directory structure as well.
I have found a PHP class that makes recursive FTP uploads and downloads easy. It can be found here
The code they used is below (The code at the top is example code for downloads, uploads, and error checking):
<?php // example
set_time_limit(0);
require 'ftp.php';
$ftp = new ftp();
$ftp->conn('host', 'username', 'password');
$ftp->get('download/demo', '/demo'); // download live "/demo" folder to local "download/demo"
$ftp->put('/demo/test', 'upload/vjtest'); // upload local "upload/vjtest" to live "/demo/test"
$arr = $ftp->getLogData();
if ($arr['error'] != "")
echo '<h2>Error:</h2>' . implode('<br />', $arr['error']);
if ($arr['ok'] != "")
echo '<h2>Success:</h2>' . implode('<br />', $arr['ok']);
class ftp {
private $conn, $login_result, $logData, $ftpUser, $ftpPass, $ftpHost, $retry, $ftpPasv, $ftpMode, $verbose, $logPath, $createMask;
// --------------------------------------------------------------------
/**
* Construct method
*
* #param array keys[passive_mode(true|false)|transfer_mode(FTP_ASCII|FTP_BINARY)|reattempts(int)|log_path|verbose(true|false)|create_mask(default:0777)]
* #return void
*/
function __construct()
{
$this->retry = (isset($o['reattempts'])) ? $o['reattempts'] : 3;
$this->ftpPasv = (isset($o['passive_mode'])) ? $o['passive_mode'] : true;
$this->ftpMode = (isset($o['transfer_mode'])) ? $o['transfer_mode'] : FTP_BINARY;
$this->verbose = (isset($o['verbose'])) ? $o['verbose'] : false;
$this->logPath = (isset($o['log_path'])) ? $o['log_path'] : dirname(__FILE__).'\log';
$this->createMask = (isset($o['create_mask'])) ? $o['create_mask'] : 0777;
}
// --------------------------------------------------------------------
/**
* Connection method
*
* #param string hostname
* #param string username
* #param string password
* #return void
*/
public function conn($hostname, $username, $password)
{
$this->ftpUser = $username;
$this->ftpPass = $password;
$this->ftpHost = $hostname;
$this->initConn();
}
// --------------------------------------------------------------------
/**
* Init connection method - connect to ftp server and set passive mode
*
* #return bool
*/
function initConn()
{
$this->conn = ftp_connect($this->ftpHost);
$this->login_result = ftp_login($this->conn, $this->ftpUser, $this->ftpPass);
if($this->conn && $this->login_result)
{
ftp_pasv($this->conn, $this->ftpPasv);
return true;
}
return false;
}
// --------------------------------------------------------------------
/**
* Put method - upload files(folders) to ftp server
*
* #param string path to destionation file/folder on ftp
* #param string path to source file/folder on local disk
* #param int only for identify reattempt, dont use this param
* #return bool
*/
public function put($destinationFile, $sourceFile, $retry = 0)
{
if(file_exists($sourceFile))
{
if(!$this->isDir($sourceFile, true))
{
$this->createSubDirs($destinationFile);
if(!ftp_put($this->conn, $destinationFile, $sourceFile, $this->ftpMode))
{
$retry++;
if($retry > $this->retry)
{
$this->logData('Error when uploading file: '.$sourceFile.' => '.$destinationFile, 'error');
return false;
}
if($this->verbose) echo 'Retry: '.$retry."\n";
$this->reconnect();
$this->put($destinationFile, $sourceFile, $retry);
}
else
{
$this->logData('Upload:'.$sourceFile.' => '.$destinationFile, 'ok');
return true;
}
}
else
{
$this->recursive($destinationFile, $sourceFile, 'put');
}
}
}
// --------------------------------------------------------------------
/**
* Get method - download files(folders) from ftp server
*
* #param string path to destionation file/folder on local disk
* #param string path to source file/folder on ftp server
* #param int only for identify reattempt, dont use this param
* #return bool
*/
public function get($destinationFile, $sourceFile, $retry = 0)
{
if(!$this->isDir($sourceFile, false))
{
if($this->verbose)echo $sourceFile.' => '.$destinationFile."\n";
$this->createSubDirs($destinationFile, false, true);
if(!ftp_get($this->conn, $destinationFile, $sourceFile, $this->ftpMode))
{
$retry++;
if($retry > $this->retry)
{
$this->logData('Error when downloading file: '.$sourceFile.' => '.$destinationFile, 'error');
return false;
}
if($this->verbose) echo 'Retry: '.$retry."\n";
$this->reconnect();
$this->get($destinationFile, $sourceFile, $retry);
}
else
{
$this->logData('Download:'.$sourceFile.' => '.$destinationFile, 'ok');
return true;
}
}
else
{
$this->recursive($destinationFile, $sourceFile, 'get');
}
}
// --------------------------------------------------------------------
/**
* Make dir method - make folder on ftp server or local disk
*
* #param string path to destionation folder on ftp or local disk
* #param bool true for local, false for ftp
* #return bool
*/
public function makeDir($dir, $local = false)
{
if($local)
{
if(!file_exists($dir) && !is_dir($dir))return mkdir($dir, $this->createMask); else return true;
}
else
{
ftp_mkdir($this->conn,$dir);
return ftp_chmod($this->conn, $this->createMask, $dir);
}
}
// --------------------------------------------------------------------
/**
* Cd up method - change working dir up
*
* #param bool true for local, false for ftp
* #return bool
*/
public function cdUp($local)
{
return $local ? chdir('..') : ftp_cdup($this->conn);
}
// --------------------------------------------------------------------
/**
* List contents of dir method - list all files in specified directory
*
* #param string path to destionation folder on ftp or local disk
* #param bool true for local, false for ftp
* #return bool
*/
public function listFiles($file, $local = false)
{
if(!$this->isDir($file, $local))return false;
if($local)
{
return scandir($file);
}
else
{
if(!preg_match('/\//', $file))
{
return ftp_nlist($this->conn, $file);
}else
{
$dirs = explode('/', $file);
foreach($dirs as $dir)
{
$this->changeDir($dir, $local);
}
$last = count($dirs)-1;
$this->cdUp($local);
$list = ftp_nlist($this->conn, $dirs[$last]);
$i = 0;
foreach($dirs as $dir)
{
if($i < $last) $this->cdUp($local);
$i++;
}
return $list;
}
}
}
// --------------------------------------------------------------------
/**
* Returns current working directory
*
* #param bool true for local, false for ftp
* #return bool
*/
public function pwd($local = false)
{
return $local ? getcwd() : ftp_pwd($this->conn);
}
// --------------------------------------------------------------------
/**
* Change current working directory
*
* #param string dir name
* #param bool true for local, false for ftp
* #return bool
*/
public function changeDir($dir, $local = false)
{
return $local ? chdir($dir) : #ftp_chdir($this->conn, $dir);
}
// --------------------------------------------------------------------
/**
* Create subdirectories
*
* #param string path
* #param bool
* #param bool true for local, false for ftp
* #param bool change current working directory back
* #return void
*/
function createSubDirs($file, $last = false, $local = false, $chDirBack = true)
{
if(preg_match('/\//',$file))
{
$origin = $this->pwd($local);
if(!$last) $file = substr($file, 0, strrpos($file,'/'));
$dirs = explode('/',$file);
foreach($dirs as $dir)
{
if(!$this->isDir($dir, $local))
{
$this->makeDir($dir, $local);
$this->changeDir($dir, $local);
}
else
{
$this->changeDir($dir, $local);
}
}
if($chDirBack) $this->changeDir($origin, $local);
}
}
// --------------------------------------------------------------------
/**
* Recursion
*
* #param string destionation file/folder
* #param string source file/folder
* #param string put or get
* #return void
*/
function recursive($destinationFile, $sourceFile, $mode)
{
$local = ($mode == 'put') ? true : false;
$list = $this->listFiles($sourceFile, $local);
if($this->verbose) echo "\n".'Folder: '.$sourceFile."\n";
$this->logData(($mode=='get')?('Download:'):('Upload:').$sourceFile.' => '.$destinationFile, 'ok');
if($this->verbose) print_r($list);
$x=0;
$z=0;
if(count($list)==2)// blank folder
{
if($mode == 'get')
$this->makeDir($destinationFile, true);
if($mode == 'put')
$this->makeDir($destinationFile);
}
foreach($list as $file)
{
if($file == '.' || $file == '..')continue;
$destFile = $destinationFile.'/'.$file;
$srcFile = $sourceFile.'/'.$file;
if($this->isDir($srcFile,$local))
{
$this->recursive($destFile, $srcFile, $mode);
}
else
{
if($local)
{
$this->put($destFile, $srcFile);
}
else
{
$this->get($destFile, $srcFile);
}
}
}
}
// --------------------------------------------------------------------
/**
* Check if is dir
*
* #param string path to folder
* #return bool
*/
public function isDir($dir, $local)
{
if($local) return is_dir($dir);
if($this->changeDir($dir))return $this->cdUp(0);
return false;
}
// --------------------------------------------------------------------
/**
* Save log data to array
*
* #param string data
* #param string type(error|ok)
* #return void
*/
function logData($data, $type)
{
$this->logData[$type][] = $data;
}
// --------------------------------------------------------------------
/**
* Get log data array
*
* #return array
*/
public function getLogData()
{
return $this->logData;
}
// --------------------------------------------------------------------
/**
* Save log data to file
*
* #return void
*/
public function logDataToFiles()
{
if(!$this->logPath) return false;
$this->makeDir($this->logPath, true);
$log = $this->getLogData();
$sep = "\n".date('y-m-d H:i:s').' ';
if($log['error'] != "")
{
$logc = date('y-m-d H:i:s').' '.join($sep,$log['error'])."\n";
$this->addToFile($this->logPath.'/'.$this->ftpUser.'-error.log',$logc);
}
if($log['ok'] != "")
{
$logc = date('y-m-d H:i:s').' '.join($sep,$log['ok'])."\n";
$this->addToFile($this->logPath.'/'.$this->ftpUser.'-ok.log',$logc);
}
}
// --------------------------------------------------------------------
/**
* Reconnect method
*
* #return void
*/
public function reconnect()
{
$this->closeConn();
$this->initConn();
}
// --------------------------------------------------------------------
/**
* Close connection method
*
* #return void
*/
public function closeConn()
{
return ftp_close($this->conn);
}
// --------------------------------------------------------------------
/**
* Write to file
*
* #param string path to file
* #param string text
* #param string fopen mode
* #return void
*/
function addToFile($file, $ins, $mode = 'a')
{
$fp = fopen($file, $mode);
fwrite($fp,$ins);
fclose($fp);
}
// --------------------------------------------------------------------
/**
* Destruct method - close connection and save log data to file
*
* #return void
*/
function __destruct()
{
$this->closeConn();
$this->logDataToFiles();
}
}
// END ftp class
/* End of file ftp.php */
/* Location: ftp.php */
This should be a comment, but its a bit long. Copying a file over FTP using PHP might be as simple as
file_put_contents($fname
, file_get_contents('FTP://ftp.example com/path/afile'));
But what do you know about where your PHP code is running? It may not have the capability to
resolve DNS names
make client connections to other/remote services
create a listening data channel (for non-passive data channel)
And we can't answer these questions for you. Hence your first step is to get a proof of concept up and running using similar code to that above before you start worrying about lots of files, directories and synchronisation.
Why the requirement to implement this in PHP?

Issue loading PHPExcel in Codeigniter

I'm trying to use PHPExcel with Codeigniter, but I'm running into issues. I extracted the class files from the PHPExcel download and placed them in the 'application/libraries' folder for Codeigniter.
However when I try to load the necessary libraries:
$this->load->library('PHPExcel');
$this->load->library('PHPExcel/IOFactory');
I get the error "Non-existent class: IOFactory".
I've checked that iofactory file is in the PHPExcel file, and it is there. Am I supposed to have the classes located somewhere else? What else am I doing wrong?
Try something like this:
$this->load->library('PHPExcel');
$xl_obj = new PHPExcel();
$reader = PHPExcel_IOFactory::createReader('Excel5');
$reader->setReadDataOnly(true);
$file = $reader->load('/PATH/FILENAME.EXT');
It works!
My method for this was to put the PHPExcel folder in /application/libraries folder, then create a wrapper file in the libraries folder;
PHPExcel.php
<?php
/**
* PHPExcel
*
* Copyright (c) 2006 - 2011 PHPExcel
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* #category PHPExcel
* #package PHPExcel
* #copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
* #license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
* #version 1.7.6, 2011-02-27
*/
/** PHPExcel root directory */
if (!defined('PHPEXCEL_ROOT')) {
define('PHPEXCEL_ROOT', dirname(__FILE__) . '/');
require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
}
/**
* PHPExcel
*
* #category PHPExcel
* #package PHPExcel
* #copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
*/
class PHPExcel
{
/**
* Document properties
*
* #var PHPExcel_DocumentProperties
*/
private $_properties;
/**
* Document security
*
* #var PHPExcel_DocumentSecurity
*/
private $_security;
/**
* Collection of Worksheet objects
*
* #var PHPExcel_Worksheet[]
*/
private $_workSheetCollection = array();
/**
* Active sheet index
*
* #var int
*/
private $_activeSheetIndex = 0;
/**
* Named ranges
*
* #var PHPExcel_NamedRange[]
*/
private $_namedRanges = array();
/**
* CellXf supervisor
*
* #var PHPExcel_Style
*/
private $_cellXfSupervisor;
/**
* CellXf collection
*
* #var PHPExcel_Style[]
*/
private $_cellXfCollection = array();
/**
* CellStyleXf collection
*
* #var PHPExcel_Style[]
*/
private $_cellStyleXfCollection = array();
/**
* Create a new PHPExcel with one Worksheet
*/
public function __construct()
{
// Initialise worksheet collection and add one worksheet
$this->_workSheetCollection = array();
$this->_workSheetCollection[] = new PHPExcel_Worksheet($this);
$this->_activeSheetIndex = 0;
// Create document properties
$this->_properties = new PHPExcel_DocumentProperties();
// Create document security
$this->_security = new PHPExcel_DocumentSecurity();
// Set named ranges
$this->_namedRanges = array();
// Create the cellXf supervisor
$this->_cellXfSupervisor = new PHPExcel_Style(true);
$this->_cellXfSupervisor->bindParent($this);
// Create the default style
$this->addCellXf(new PHPExcel_Style);
$this->addCellStyleXf(new PHPExcel_Style);
}
public function disconnectWorksheets() {
foreach($this->_workSheetCollection as $k => &$worksheet) {
$worksheet->disconnectCells();
$this->_workSheetCollection[$k] = null;
}
unset($worksheet);
$this->_workSheetCollection = array();
}
/**
* Get properties
*
* #return PHPExcel_DocumentProperties
*/
public function getProperties()
{
return $this->_properties;
}
/**
* Set properties
*
* #param PHPExcel_DocumentProperties $pValue
*/
public function setProperties(PHPExcel_DocumentProperties $pValue)
{
$this->_properties = $pValue;
}
/**
* Get security
*
* #return PHPExcel_DocumentSecurity
*/
public function getSecurity()
{
return $this->_security;
}
/**
* Set security
*
* #param PHPExcel_DocumentSecurity $pValue
*/
public function setSecurity(PHPExcel_DocumentSecurity $pValue)
{
$this->_security = $pValue;
}
/**
* Get active sheet
*
* #return PHPExcel_Worksheet
*/
public function getActiveSheet()
{
return $this->_workSheetCollection[$this->_activeSheetIndex];
}
/**
* Create sheet and add it to this workbook
*
* #return PHPExcel_Worksheet
*/
public function createSheet($iSheetIndex = null)
{
$newSheet = new PHPExcel_Worksheet($this);
$this->addSheet($newSheet, $iSheetIndex);
return $newSheet;
}
/**
* Add sheet
*
* #param PHPExcel_Worksheet $pSheet
* #param int|null $iSheetIndex Index where sheet should go (0,1,..., or null for last)
* #return PHPExcel_Worksheet
* #throws Exception
*/
public function addSheet(PHPExcel_Worksheet $pSheet = null, $iSheetIndex = null)
{
if(is_null($iSheetIndex))
{
$this->_workSheetCollection[] = $pSheet;
}
else
{
// Insert the sheet at the requested index
array_splice(
$this->_workSheetCollection,
$iSheetIndex,
0,
array($pSheet)
);
// Adjust active sheet index if necessary
if ($this->_activeSheetIndex >= $iSheetIndex) {
++$this->_activeSheetIndex;
}
}
return $pSheet;
}
/**
* Remove sheet by index
*
* #param int $pIndex Active sheet index
* #throws Exception
*/
public function removeSheetByIndex($pIndex = 0)
{
if ($pIndex > count($this->_workSheetCollection) - 1) {
throw new Exception("Sheet index is out of bounds.");
} else {
array_splice($this->_workSheetCollection, $pIndex, 1);
}
}
/**
* Get sheet by index
*
* #param int $pIndex Sheet index
* #return PHPExcel_Worksheet
* #throws Exception
*/
public function getSheet($pIndex = 0)
{
if ($pIndex > count($this->_workSheetCollection) - 1) {
throw new Exception("Sheet index is out of bounds.");
} else {
return $this->_workSheetCollection[$pIndex];
}
}
/**
* Get all sheets
*
* #return PHPExcel_Worksheet[]
*/
public function getAllSheets()
{
return $this->_workSheetCollection;
}
/**
* Get sheet by name
*
* #param string $pName Sheet name
* #return PHPExcel_Worksheet
* #throws Exception
*/
public function getSheetByName($pName = '')
{
$worksheetCount = count($this->_workSheetCollection);
for ($i = 0; $i < $worksheetCount; ++$i) {
if ($this->_workSheetCollection[$i]->getTitle() == $pName) {
return $this->_workSheetCollection[$i];
}
}
return null;
}
/**
* Get index for sheet
*
* #param PHPExcel_Worksheet $pSheet
* #return Sheet index
* #throws Exception
*/
public function getIndex(PHPExcel_Worksheet $pSheet)
{
foreach ($this->_workSheetCollection as $key => $value) {
if ($value->getHashCode() == $pSheet->getHashCode()) {
return $key;
}
}
}
/**
* Set index for sheet by sheet name.
*
* #param string $sheetName Sheet name to modify index for
* #param int $newIndex New index for the sheet
* #return New sheet index
* #throws Exception
*/
public function setIndexByName($sheetName, $newIndex)
{
$oldIndex = $this->getIndex($this->getSheetByName($sheetName));
$pSheet = array_splice(
$this->_workSheetCollection,
$oldIndex,
1
);
array_splice(
$this->_workSheetCollection,
$newIndex,
0,
$pSheet
);
return $newIndex;
}
/**
* Get sheet count
*
* #return int
*/
public function getSheetCount()
{
return count($this->_workSheetCollection);
}
/**
* Get active sheet index
*
* #return int Active sheet index
*/
public function getActiveSheetIndex()
{
return $this->_activeSheetIndex;
}
/**
* Set active sheet index
*
* #param int $pIndex Active sheet index
* #throws Exception
* #return PHPExcel_Worksheet
*/
public function setActiveSheetIndex($pIndex = 0)
{
if ($pIndex > count($this->_workSheetCollection) - 1) {
throw new Exception("Active sheet index is out of bounds.");
} else {
$this->_activeSheetIndex = $pIndex;
}
return $this->getActiveSheet();
}
/**
* Set active sheet index by name
*
* #param string $pValue Sheet title
* #return PHPExcel_Worksheet
* #throws Exception
*/
public function setActiveSheetIndexByName($pValue = '')
{
if (($worksheet = $this->getSheetByName($pValue)) instanceof PHPExcel_Worksheet) {
$this->setActiveSheetIndex($worksheet->getParent()->getIndex($worksheet));
return $worksheet;
}
throw new Exception('Workbook does not contain sheet:' . $pValue);
}
/**
* Get sheet names
*
* #return string[]
*/
public function getSheetNames()
{
$returnValue = array();
$worksheetCount = $this->getSheetCount();
for ($i = 0; $i < $worksheetCount; ++$i) {
array_push($returnValue, $this->getSheet($i)->getTitle());
}
return $returnValue;
}
/**
* Add external sheet
*
* #param PHPExcel_Worksheet $pSheet External sheet to add
* #param int|null $iSheetIndex Index where sheet should go (0,1,..., or null for last)
* #throws Exception
* #return PHPExcel_Worksheet
*/
public function addExternalSheet(PHPExcel_Worksheet $pSheet, $iSheetIndex = null) {
if (!is_null($this->getSheetByName($pSheet->getTitle()))) {
throw new Exception("Workbook already contains a worksheet named '{$pSheet->getTitle()}'. Rename the external sheet first.");
}
// count how many cellXfs there are in this workbook currently, we will need this below
$countCellXfs = count($this->_cellXfCollection);
// copy all the shared cellXfs from the external workbook and append them to the current
foreach ($pSheet->getParent()->getCellXfCollection() as $cellXf) {
$this->addCellXf(clone $cellXf);
}
// move sheet to this workbook
$pSheet->rebindParent($this);
// update the cellXfs
foreach ($pSheet->getCellCollection(false) as $cellID) {
$cell = $pSheet->getCell($cellID);
$cell->setXfIndex( $cell->getXfIndex() + $countCellXfs );
}
return $this->addSheet($pSheet, $iSheetIndex);
}
/**
* Get named ranges
*
* #return PHPExcel_NamedRange[]
*/
public function getNamedRanges() {
return $this->_namedRanges;
}
/**
* Add named range
*
* #param PHPExcel_NamedRange $namedRange
* #return PHPExcel
*/
public function addNamedRange(PHPExcel_NamedRange $namedRange) {
if ($namedRange->getScope() == null) {
// global scope
$this->_namedRanges[$namedRange->getName()] = $namedRange;
} else {
// local scope
$this->_namedRanges[$namedRange->getScope()->getTitle().'!'.$namedRange->getName()] = $namedRange;
}
return true;
}
/**
* Get named range
*
* #param string $namedRange
* #param PHPExcel_Worksheet|null $pSheet Scope. Use null for global scope
* #return PHPExcel_NamedRange|null
*/
public function getNamedRange($namedRange, PHPExcel_Worksheet $pSheet = null) {
$returnValue = null;
if ($namedRange != '' && !is_null($namedRange)) {
// first look for global defined name
if (isset($this->_namedRanges[$namedRange])) {
$returnValue = $this->_namedRanges[$namedRange];
}
// then look for local defined name (has priority over global defined name if both names exist)
if (!is_null($pSheet) && isset($this->_namedRanges[$pSheet->getTitle() . '!' . $namedRange])) {
$returnValue = $this->_namedRanges[$pSheet->getTitle() . '!' . $namedRange];
}
}
return $returnValue;
}
/**
* Remove named range
*
* #param string $namedRange
* #param PHPExcel_Worksheet|null $pSheet. Scope. Use null for global scope.
* #return PHPExcel
*/
public function removeNamedRange($namedRange, PHPExcel_Worksheet $pSheet = null) {
if (is_null($pSheet)) {
if (isset($this->_namedRanges[$namedRange])) {
unset($this->_namedRanges[$namedRange]);
}
} else {
if (isset($this->_namedRanges[$pSheet->getTitle() . '!' . $namedRange])) {
unset($this->_namedRanges[$pSheet->getTitle() . '!' . $namedRange]);
}
}
return $this;
}
/**
* Get worksheet iterator
*
* #return PHPExcel_WorksheetIterator
*/
public function getWorksheetIterator() {
return new PHPExcel_WorksheetIterator($this);
}
/**
* Copy workbook (!= clone!)
*
* #return PHPExcel
*/
public function copy() {
$copied = clone $this;
$worksheetCount = count($this->_workSheetCollection);
for ($i = 0; $i < $worksheetCount; ++$i) {
$this->_workSheetCollection[$i] = $this->_workSheetCollection[$i]->copy();
$this->_workSheetCollection[$i]->rebindParent($this);
}
return $copied;
}
/**
* Implement PHP __clone to create a deep clone, not just a shallow copy.
*/
public function __clone() {
foreach($this as $key => $val) {
if (is_object($val) || (is_array($val))) {
$this->{$key} = unserialize(serialize($val));
}
}
}
/**
* Get the workbook collection of cellXfs
*
* #return PHPExcel_Style[]
*/
public function getCellXfCollection()
{
return $this->_cellXfCollection;
}
/**
* Get cellXf by index
*
* #param int $index
* #return PHPExcel_Style
*/
public function getCellXfByIndex($pIndex = 0)
{
return $this->_cellXfCollection[$pIndex];
}
/**
* Get cellXf by hash code
*
* #param string $pValue
* #return PHPExcel_Style|false
*/
public function getCellXfByHashCode($pValue = '')
{
foreach ($this->_cellXfCollection as $cellXf) {
if ($cellXf->getHashCode() == $pValue) {
return $cellXf;
}
}
return false;
}
/**
* Get default style
*
* #return PHPExcel_Style
* #throws Exception
*/
public function getDefaultStyle()
{
if (isset($this->_cellXfCollection[0])) {
return $this->_cellXfCollection[0];
}
throw new Exception('No default style found for this workbook');
}
/**
* Add a cellXf to the workbook
*
* #param PHPExcel_Style
*/
public function addCellXf(PHPExcel_Style $style)
{
$this->_cellXfCollection[] = $style;
$style->setIndex(count($this->_cellXfCollection) - 1);
}
/**
* Remove cellXf by index. It is ensured that all cells get their xf index updated.
*
* #param int $pIndex Index to cellXf
* #throws Exception
*/
public function removeCellXfByIndex($pIndex = 0)
{
if ($pIndex > count($this->_cellXfCollection) - 1) {
throw new Exception("CellXf index is out of bounds.");
} else {
// first remove the cellXf
array_splice($this->_cellXfCollection, $pIndex, 1);
// then update cellXf indexes for cells
foreach ($this->_workSheetCollection as $worksheet) {
foreach ($worksheet->getCellCollection(false) as $cellID) {
$cell = $worksheet->getCell($cellID);
$xfIndex = $cell->getXfIndex();
if ($xfIndex > $pIndex ) {
// decrease xf index by 1
$cell->setXfIndex($xfIndex - 1);
} else if ($xfIndex == $pIndex) {
// set to default xf index 0
$cell->setXfIndex(0);
}
}
}
}
}
/**
* Get the cellXf supervisor
*
* #return PHPExcel_Style
*/
public function getCellXfSupervisor()
{
return $this->_cellXfSupervisor;
}
/**
* Get the workbook collection of cellStyleXfs
*
* #return PHPExcel_Style[]
*/
public function getCellStyleXfCollection()
{
return $this->_cellStyleXfCollection;
}
/**
* Get cellStyleXf by index
*
* #param int $pIndex
* #return PHPExcel_Style
*/
public function getCellStyleXfByIndex($pIndex = 0)
{
return $this->_cellStyleXfCollection[$pIndex];
}
/**
* Get cellStyleXf by hash code
*
* #param string $pValue
* #return PHPExcel_Style|false
*/
public function getCellStyleXfByHashCode($pValue = '')
{
foreach ($this->_cellXfStyleCollection as $cellStyleXf) {
if ($cellStyleXf->getHashCode() == $pValue) {
return $cellStyleXf;
}
}
return false;
}
/**
* Add a cellStyleXf to the workbook
*
* #param PHPExcel_Style $pStyle
*/
public function addCellStyleXf(PHPExcel_Style $pStyle)
{
$this->_cellStyleXfCollection[] = $pStyle;
$pStyle->setIndex(count($this->_cellStyleXfCollection) - 1);
}
/**
* Remove cellStyleXf by index
*
* #param int $pIndex
* #throws Exception
*/
public function removeCellStyleXfByIndex($pIndex = 0)
{
if ($pIndex > count($this->_cellStyleXfCollection) - 1) {
throw new Exception("CellStyleXf index is out of bounds.");
} else {
array_splice($this->_cellStyleXfCollection, $pIndex, 1);
}
}
/**
* Eliminate all unneeded cellXf and afterwards update the xfIndex for all cells
* and columns in the workbook
*/
public function garbageCollect()
{
// how many references are there to each cellXf ?
$countReferencesCellXf = array();
foreach ($this->_cellXfCollection as $index => $cellXf) {
$countReferencesCellXf[$index] = 0;
}
foreach ($this->getWorksheetIterator() as $sheet) {
// from cells
foreach ($sheet->getCellCollection(false) as $cellID) {
$cell = $sheet->getCell($cellID);
++$countReferencesCellXf[$cell->getXfIndex()];
}
// from row dimensions
foreach ($sheet->getRowDimensions() as $rowDimension) {
if ($rowDimension->getXfIndex() !== null) {
++$countReferencesCellXf[$rowDimension->getXfIndex()];
}
}
// from column dimensions
foreach ($sheet->getColumnDimensions() as $columnDimension) {
++$countReferencesCellXf[$columnDimension->getXfIndex()];
}
}
// remove cellXfs without references and create mapping so we can update xfIndex
// for all cells and columns
$countNeededCellXfs = 0;
foreach ($this->_cellXfCollection as $index => $cellXf) {
if ($countReferencesCellXf[$index] > 0 || $index == 0) { // we must never remove the first cellXf
++$countNeededCellXfs;
} else {
unset($this->_cellXfCollection[$index]);
}
$map[$index] = $countNeededCellXfs - 1;
}
$this->_cellXfCollection = array_values($this->_cellXfCollection);
// update the index for all cellXfs
foreach ($this->_cellXfCollection as $i => $cellXf) {
$cellXf->setIndex($i);
}
// make sure there is always at least one cellXf (there should be)
if (count($this->_cellXfCollection) == 0) {
$this->_cellXfCollection[] = new PHPExcel_Style();
}
// update the xfIndex for all cells, row dimensions, column dimensions
foreach ($this->getWorksheetIterator() as $sheet) {
// for all cells
foreach ($sheet->getCellCollection(false) as $cellID) {
$cell = $sheet->getCell($cellID);
$cell->setXfIndex( $map[$cell->getXfIndex()] );
}
// for all row dimensions
foreach ($sheet->getRowDimensions() as $rowDimension) {
if ($rowDimension->getXfIndex() !== null) {
$rowDimension->setXfIndex( $map[$rowDimension->getXfIndex()] );
}
}
// for all column dimensions
foreach ($sheet->getColumnDimensions() as $columnDimension) {
$columnDimension->setXfIndex( $map[$columnDimension->getXfIndex()] );
}
}
// also do garbage collection for all the sheets
foreach ($this->getWorksheetIterator() as $sheet) {
$sheet->garbageCollect();
}
}
}
Then in my contoller;
$this->load->library('PHPExcel');
// Create new PHPExcel object
$excel_obj = new PHPExcel();
// Set properties
$excel_obj->getProperties()->setCreator($params['author'])
->setLastModifiedBy($params['author'])
->setTitle($params['title'])
->setSubject($params['subject'])
->setDescription($params['description']);

PHP: How to read "Title" of font from .ttf file?

I really need to be able to extract the metadata from a .ttf true type font file.
I'm building a central database of all the fonts all our designers use (they're forever swapping fonts via email to take over design elements, etc). I want to get all the fonts, some have silly names like 00001.ttf, so file name is no help, but I know the fonts have metadata, I need some way to extract that in PHP.
Then I can create a loop to look through the directories I've specified, get this data (and any other data I can get at the same time, and add it to a database.
I just really need help with the reading of this metadata part.
I came across this link. It will do what you want (I've tested it and posted results). Just pass the class the path of the TTF file you want to parse the data out of. then use $fontinfo[1].' '.$fontinfo[2] for the name.
In case you don't want to register, here is the class
Resulting Data
Array
(
[1] => Almonte Snow
[2] => Regular
[3] => RayLarabie: Almonte Snow: 2000
[4] => Almonte Snow
[5] => Version 2.000 2004
[6] => AlmonteSnow
[8] => Ray Larabie
[9] => Ray Larabie
[10] => Larabie Fonts is able to offer unique free fonts through the generous support of visitors to the site. Making fonts is my full-time job and every donation, in any amount, enables me to continue running the site and creating new fonts. If you would like to support Larabie Fonts visit www.larabiefonts.com for details.
[11] => http://www.larabiefonts.com
[12] => http://www.typodermic.com
)
Usage
<?php
include 'ttfInfo.class.php';
$fontinfo = getFontInfo('c:\windows\fonts\_LDS_almosnow.ttf');
echo '<pre>';
print_r($fontinfo);
echo '</pre>';
?>
ttfInfo.class.php
<?php
/**
* ttfInfo class
* Retrieve data stored in a TTF files 'name' table
*
* #original author Unknown
* found at http://www.phpclasses.org/browse/package/2144.html
*
* #ported for used on http://www.nufont.com
* #author Jason Arencibia
* #version 0.2
* #copyright (c) 2006 GrayTap Media
* #website http://www.graytap.com
* #license GPL 2.0
* #access public
*
* #todo: Make it Retrieve additional information from other tables
*
*/
class ttfInfo {
/**
* variable $_dirRestriction
* Restrict the resource pointer to this directory and above.
* Change to 1 for to allow the class to look outside of it current directory
* #protected
* #var int
*/
protected $_dirRestriction = 1;
/**
* variable $_dirRestriction
* Restrict the resource pointer to this directory and above.
* Change to 1 for nested directories
* #protected
* #var int
*/
protected $_recursive = 0;
/**
* variable $fontsdir
* This is to declare this variable as protected
* don't edit this!!!
* #protected
*/
protected $fontsdir;
/**
* variable $filename
* This is to declare this varable as protected
* don't edit this!!!
* #protected
*/
protected $filename;
/**
* function setFontFile()
* set the filename
* #public
* #param string $data the new value
* #return object reference to this
*/
public function setFontFile($data)
{
if ($this->_dirRestriction && preg_match('[\.\/|\.\.\/]', $data))
{
$this->exitClass('Error: Directory restriction is enforced!');
}
$this->filename = $data;
return $this;
} // public function setFontFile
/**
* function setFontsDir()
* set the Font Directory
* #public
* #param string $data the new value
* #return object referrence to this
*/
public function setFontsDir($data)
{
if ($this->_dirRestriction && preg_match('[\.\/|\.\.\/]', $data))
{
$this->exitClass('Error: Directory restriction is enforced!');
}
$this->fontsdir = $data;
return $this;
} // public function setFontsDir
/**
* function readFontsDir()
* #public
* #return information contained in the TTF 'name' table of all fonts in a directory.
*/
public function readFontsDir()
{
if (empty($this->fontsdir)) { $this->exitClass('Error: Fonts Directory has not been set with setFontsDir().'); }
if (empty($this->backupDir)){ $this->backupDir = $this->fontsdir; }
$this->array = array();
$d = dir($this->fontsdir);
while (false !== ($e = $d->read()))
{
if($e != '.' && $e != '..')
{
$e = $this->fontsdir . $e;
if($this->_recursive && is_dir($e))
{
$this->setFontsDir($e);
$this->array = array_merge($this->array, readFontsDir());
}
else if ($this->is_ttf($e) === true)
{
$this->setFontFile($e);
$this->array[$e] = $this->getFontInfo();
}
}
}
if (!empty($this->backupDir)){ $this->fontsdir = $this->backupDir; }
$d->close();
return $this;
} // public function readFontsDir
/**
* function setProtectedVar()
* #public
* #param string $var the new variable
* #param string $data the new value
* #return object reference to this
* DISABLED, NO REAL USE YET
public function setProtectedVar($var, $data)
{
if ($var == 'filename')
{
$this->setFontFile($data);
} else {
//if (isset($var) && !empty($data))
$this->$var = $data;
}
return $this;
}
*/
/**
* function getFontInfo()
* #public
* #return information contained in the TTF 'name' table.
*/
public function getFontInfo()
{
$fd = fopen ($this->filename, "r");
$this->text = fread ($fd, filesize($this->filename));
fclose ($fd);
$number_of_tables = hexdec($this->dec2ord($this->text[4]).$this->dec2ord($this->text[5]));
for ($i=0;$i<$number_of_tables;$i++)
{
$tag = $this->text[12+$i*16].$this->text[12+$i*16+1].$this->text[12+$i*16+2].$this->text[12+$i*16+3];
if ($tag == 'name')
{
$this->ntOffset = hexdec(
$this->dec2ord($this->text[12+$i*16+8]).$this->dec2ord($this->text[12+$i*16+8+1]).
$this->dec2ord($this->text[12+$i*16+8+2]).$this->dec2ord($this->text[12+$i*16+8+3]));
$offset_storage_dec = hexdec($this->dec2ord($this->text[$this->ntOffset+4]).$this->dec2ord($this->text[$this->ntOffset+5]));
$number_name_records_dec = hexdec($this->dec2ord($this->text[$this->ntOffset+2]).$this->dec2ord($this->text[$this->ntOffset+3]));
}
}
$storage_dec = $offset_storage_dec + $this->ntOffset;
$storage_hex = strtoupper(dechex($storage_dec));
for ($j=0;$j<$number_name_records_dec;$j++)
{
$platform_id_dec = hexdec($this->dec2ord($this->text[$this->ntOffset+6+$j*12+0]).$this->dec2ord($this->text[$this->ntOffset+6+$j*12+1]));
$name_id_dec = hexdec($this->dec2ord($this->text[$this->ntOffset+6+$j*12+6]).$this->dec2ord($this->text[$this->ntOffset+6+$j*12+7]));
$string_length_dec = hexdec($this->dec2ord($this->text[$this->ntOffset+6+$j*12+8]).$this->dec2ord($this->text[$this->ntOffset+6+$j*12+9]));
$string_offset_dec = hexdec($this->dec2ord($this->text[$this->ntOffset+6+$j*12+10]).$this->dec2ord($this->text[$this->ntOffset+6+$j*12+11]));
if (!empty($name_id_dec) and empty($font_tags[$name_id_dec]))
{
for($l=0;$l<$string_length_dec;$l++)
{
if (ord($this->text[$storage_dec+$string_offset_dec+$l]) == '0') { continue; }
else { $font_tags[$name_id_dec] .= ($this->text[$storage_dec+$string_offset_dec+$l]); }
}
}
}
return $font_tags;
} // public function getFontInfo
/**
* function getCopyright()
* #public
* #return 'Copyright notice' contained in the TTF 'name' table at index 0
*/
public function getCopyright()
{
$this->info = $this->getFontInfo();
return $this->info[0];
} // public function getCopyright
/**
* function getFontFamily()
* #public
* #return 'Font Family name' contained in the TTF 'name' table at index 1
*/
public function getFontFamily()
{
$this->info = $this->getFontInfo();
return $this->info[1];
} // public function getFontFamily
/**
* function getFontSubFamily()
* #public
* #return 'Font Subfamily name' contained in the TTF 'name' table at index 2
*/
public function getFontSubFamily()
{
$this->info = $this->getFontInfo();
return $this->info[2];
} // public function getFontSubFamily
/**
* function getFontId()
* #public
* #return 'Unique font identifier' contained in the TTF 'name' table at index 3
*/
public function getFontId()
{
$this->info = $this->getFontInfo();
return $this->info[3];
} // public function getFontId
/**
* function getFullFontName()
* #public
* #return 'Full font name' contained in the TTF 'name' table at index 4
*/
public function getFullFontName()
{
$this->info = $this->getFontInfo();
return $this->info[4];
} // public function getFullFontName
/**
* function dec2ord()
* Used to lessen redundant calls to multiple functions.
* #protected
* #return object
*/
protected function dec2ord($dec)
{
return $this->dec2hex(ord($dec));
} // protected function dec2ord
/**
* function dec2hex()
* private function to perform Hexadecimal to decimal with proper padding.
* #protected
* #return object
*/
protected function dec2hex($dec)
{
return str_repeat('0', 2-strlen(($hex=strtoupper(dechex($dec))))) . $hex;
} // protected function dec2hex
/**
* function dec2hex()
* private function to perform Hexadecimal to decimal with proper padding.
* #protected
* #return object
*/
protected function exitClass($message)
{
echo $message;
exit;
} // protected function dec2hex
/**
* function dec2hex()
* private helper function to test in the file in question is a ttf.
* #protected
* #return object
*/
protected function is_ttf($file)
{
$ext = explode('.', $file);
$ext = $ext[count($ext)-1];
return preg_match("/ttf$/i",$ext) ? true : false;
} // protected function is_ttf
} // class ttfInfo
function getFontInfo($resource)
{
$ttfInfo = new ttfInfo;
$ttfInfo->setFontFile($resource);
return $ttfInfo->getFontInfo();
}
?>
Update 2021
Here is an updated version of the class with some fixes
https://github.com/HusamAamer/TTFInfo.git
Very similar to the previously posted answer... I've been using this class for a long time now.
class fontAttributes extends baseClass
{
// --- ATTRIBUTES ---
/**
* #access private
* #var string
*/
private $_fileName = NULL ; // Name of the truetype font file
/**
* #access private
* #var string
*/
private $_copyright = NULL ; // Copyright
/**
* #access private
* #var string
*/
private $_fontFamily = NULL ; // Font Family
/**
* #access private
* #var string
*/
private $_fontSubFamily = NULL ; // Font SubFamily
/**
* #access private
* #var string
*/
private $_fontIdentifier = NULL ; // Font Unique Identifier
/**
* #access private
* #var string
*/
private $_fontName = NULL ; // Font Name
/**
* #access private
* #var string
*/
private $_fontVersion = NULL ; // Font Version
/**
* #access private
* #var string
*/
private $_postscriptName = NULL ; // Postscript Name
/**
* #access private
* #var string
*/
private $_trademark = NULL ; // Trademark
// --- OPERATIONS ---
private function _returnValue($inString)
{
if (ord($inString) == 0) {
if (function_exists('mb_convert_encoding')) {
return mb_convert_encoding($inString,"UTF-8","UTF-16");
} else {
return str_replace(chr(00),'',$inString);
}
} else {
return $inString;
}
} // function _returnValue()
/**
* #access public
* #return integer
*/
public function getCopyright()
{
return $this->_returnValue($this->_copyright);
} // function getCopyright()
/**
* #access public
* #return integer
*/
public function getFontFamily()
{
return $this->_returnValue($this->_fontFamily);
} // function getFontFamily()
/**
* #access public
* #return integer
*/
public function getFontSubFamily()
{
return $this->_returnValue($this->_fontSubFamily);
} // function getFontSubFamily()
/**
* #access public
* #return integer
*/
public function getFontIdentifier()
{
return $this->_returnValue($this->_fontIdentifier);
} // function getFontIdentifier()
/**
* #access public
* #return integer
*/
public function getFontName()
{
return $this->_returnValue($this->_fontName);
} // function getFontName()
/**
* #access public
* #return integer
*/
public function getFontVersion()
{
return $this->_returnValue($this->_fontVersion);
} // function getFontVersion()
/**
* #access public
* #return integer
*/
public function getPostscriptName()
{
return $this->_returnValue($this->_postscriptName);
} // function getPostscriptName()
/**
* #access public
* #return integer
*/
public function getTrademark()
{
return $this->_returnValue($this->_trademark);
} // function getTrademark()
/**
* Convert a big-endian word or longword value to an integer
*
* #access private
* #return integer
*/
private function _UConvert($bytesValue,$byteCount)
{
$retVal = 0;
$bytesLength = strlen($bytesValue);
for ($i=0; $i < $bytesLength; $i++) {
$tmpVal = ord($bytesValue{$i});
$t = pow(256,($byteCount-$i-1));
$retVal += $tmpVal*$t;
}
return $retVal;
} // function UConvert()
/**
* Convert a big-endian word value to an integer
*
* #access private
* #return integer
*/
private function _USHORT($stringValue) {
return $this->_UConvert($stringValue,2);
}
/**
* Convert a big-endian word value to an integer
*
* #access private
* #return integer
*/
private function _ULONG($stringValue) {
return $this->_UConvert($stringValue,4);
}
/**
* Read the Font Attributes
*
* #access private
* #return integer
*/
private function readFontAttributes() {
$fontHandle = fopen($this->_fileName, "rb");
// Read the file header
$TT_OFFSET_TABLE = fread($fontHandle, 12);
$uMajorVersion = $this->_USHORT(substr($TT_OFFSET_TABLE,0,2));
$uMinorVersion = $this->_USHORT(substr($TT_OFFSET_TABLE,2,2));
$uNumOfTables = $this->_USHORT(substr($TT_OFFSET_TABLE,4,2));
// $uSearchRange = $this->_USHORT(substr($TT_OFFSET_TABLE,6,2));
// $uEntrySelector = $this->_USHORT(substr($TT_OFFSET_TABLE,8,2));
// $uRangeShift = $this->_USHORT(substr($TT_OFFSET_TABLE,10,2));
// Check is this is a true type font and the version is 1.0
if ($uMajorVersion != 1 || $uMinorVersion != 0) {
fclose($fontHandle);
throw new Exception($this->_fileName.' is not a Truetype font file') ;
}
// Look for details of the name table
$nameTableFound = false;
for ($t=0; $t < $uNumOfTables; $t++) {
$TT_TABLE_DIRECTORY = fread($fontHandle, 16);
$szTag = substr($TT_TABLE_DIRECTORY,0,4);
if (strtolower($szTag) == 'name') {
// $uCheckSum = $this->_ULONG(substr($TT_TABLE_DIRECTORY,4,4));
$uOffset = $this->_ULONG(substr($TT_TABLE_DIRECTORY,8,4));
// $uLength = $this->_ULONG(substr($TT_TABLE_DIRECTORY,12,4));
$nameTableFound = true;
break;
}
}
if (!$nameTableFound) {
fclose($fontHandle);
throw new Exception('Can\'t find name table in '.$this->_fileName) ;
}
// Set offset to the start of the name table
fseek($fontHandle,$uOffset,SEEK_SET);
$TT_NAME_TABLE_HEADER = fread($fontHandle, 6);
// $uFSelector = $this->_USHORT(substr($TT_NAME_TABLE_HEADER,0,2));
$uNRCount = $this->_USHORT(substr($TT_NAME_TABLE_HEADER,2,2));
$uStorageOffset = $this->_USHORT(substr($TT_NAME_TABLE_HEADER,4,2));
$attributeCount = 0;
for ($a=0; $a < $uNRCount; $a++) {
$TT_NAME_RECORD = fread($fontHandle, 12);
$uNameID = $this->_USHORT(substr($TT_NAME_RECORD,6,2));
if ($uNameID <= 7) {
// $uPlatformID = $this->_USHORT(substr($TT_NAME_RECORD,0,2));
$uEncodingID = $this->_USHORT(substr($TT_NAME_RECORD,2,2));
// $uLanguageID = $this->_USHORT(substr($TT_NAME_RECORD,4,2));
$uStringLength = $this->_USHORT(substr($TT_NAME_RECORD,8,2));
$uStringOffset = $this->_USHORT(substr($TT_NAME_RECORD,10,2));
if ($uStringLength > 0) {
$nPos = ftell($fontHandle);
fseek($fontHandle,$uOffset + $uStringOffset + $uStorageOffset,SEEK_SET);
$testValue = fread($fontHandle, $uStringLength);
if (trim($testValue) > '') {
switch ($uNameID) {
case 0 : if ($this->_copyright == NULL) {
$this->_copyright = $testValue;
$attributeCount++;
}
break;
case 1 : if ($this->_fontFamily == NULL) {
$this->_fontFamily = $testValue;
$attributeCount++;
}
break;
case 2 : if ($this->_fontSubFamily == NULL) {
$this->_fontSubFamily = $testValue;
$attributeCount++;
}
break;
case 3 : if ($this->_fontIdentifier == NULL) {
$this->_fontIdentifier = $testValue;
$attributeCount++;
}
break;
case 4 : if ($this->_fontName == NULL) {
$this->_fontName = $testValue;
$attributeCount++;
}
break;
case 5 : if ($this->_fontVersion == NULL) {
$this->_fontVersion = $testValue;
$attributeCount++;
}
break;
case 6 : if ($this->_postscriptName == NULL) {
$this->_postscriptName = $testValue;
$attributeCount++;
}
break;
case 7 : if ($this->_trademark == NULL) {
$this->_trademark = $testValue;
$attributeCount++;
}
break;
}
}
fseek($fontHandle,$nPos,SEEK_SET);
}
}
if ($attributeCount > 7) {
break;
}
}
fclose($fontHandle);
return true;
}
/**
* #access constructor
* #return void
*/
function __construct($fileName='') {
if ($fileName == '') {
throw new Exception('Font File has not been specified') ;
}
$this->_fileName = $fileName;
if (!file_exists($this->_fileName)) {
throw new Exception($this->_fileName.' does not exist') ;
} elseif (!is_readable($this->_fileName)) {
throw new Exception($this->_fileName.' is not a readable file') ;
}
return $this->readFontAttributes();
} // function constructor()
} /* end of class fontAttributes */
Why reinvent the wheel when the fine people at DOMPDF project has already done the work for you? Take a look at php-font-lib # https://github.com/PhenX/php-font-lib. This has all the features that you have asked for and supports other font formats as well. Look at the demo UI # http://pxd.me/php-font-lib/www/font_explorer.html to get an idea about what kind of information you can get from this library.

Categories