I've setup my server with Yii2 and Humhub ext,
What i'm trying to do is set a rest api to it , but I get 500 Internal server error :
"message": "Cannot declare class humhub\modules\content\models\Content, because the name is already in use",
"file": "***\content\models\Content.php",
The first class is :
<?php
namespace app\models;
use Yii;
include '../humhub/modules/content/models/content.php';
class Content extends \humhub\modules\content\models\Content
{
public function getPosts()
{
return $this->hasMany(Post::className(), ['id' => 'object_id']);
}
}
The second class is (pretty big):
<?php
/**
* #link https://www.humhub.org/
* #copyright Copyright (c) 2017 HumHub GmbH & Co. KG
* #license https://www.humhub.com/licences
*/
namespace humhub\modules\content\models;
include __DIR__ .'/../../../modules\content\models\ContentDeprecated.php';
use Yii;
use humhub\modules\user\components\PermissionManager;
use yii\base\Exception;
use yii\helpers\Url;
use humhub\modules\user\models\User;
use humhub\modules\space\models\Space;
use humhub\modules\content\components\ContentActiveRecord;
use humhub\modules\content\components\ContentContainerActiveRecord;
use humhub\modules\content\permissions\ManageContent;
use yii\rbac\Permission;
/**
* This is the model class for table "content".
*
*
* The followings are the available columns in table 'content':
* #property integer $id
* #property string $guid
* #property string $object_model
* #property integer $object_id
* #property integer $visibility
* #property integer $pinned
* #property string $archived
* #property string $created_at
* #property integer $created_by
* #property string $updated_at
* #property integer $updated_by
* #property ContentContainer $contentContainer
*
* #since 0.5
*/
class Content extends ContentDeprecated
{
/**
* A array of user objects which should informed about this new content.
*
* #var array User
*/
public $notifyUsersOfNewContent = [];
/**
* #var int The private visibility mode (e.g. for space member content or user profile posts for friends)
*/
const VISIBILITY_PRIVATE = 0;
/**
* #var int Public visibility mode, e.g. content which are visibile for followers
*/
const VISIBILITY_PUBLIC = 1;
/**
* #var int Owner visibility mode, only visible for contentContainer + content owner
*/
const VISIBILITY_OWNER = 2;
/**
* #var ContentContainerActiveRecord the Container (e.g. Space or User) where this content belongs to.
*/
protected $_container = null;
/**
* #inheritdoc
*/
public function behaviors()
{
return [
[
'class' => \humhub\components\behaviors\PolymorphicRelation::className(),
'mustBeInstanceOf' => array(ContentActiveRecord::className()),
],
[
'class' => \humhub\components\behaviors\GUID::className(),
],
];
}
/**
* #inheritdoc
*/
public static function tableName()
{
return 'content';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['object_id', 'visibility', 'pinned'], 'integer'],
[['archived'], 'safe'],
[['guid'], 'string', 'max' => 45],
[['object_model'], 'string', 'max' => 100],
[['object_model', 'object_id'], 'unique', 'targetAttribute' => ['object_model', 'object_id'], 'message' => 'The combination of Object Model and Object ID has already been taken.'],
[['guid'], 'unique']
];
}
/**
* Returns a Content Object by given Class and ID
*
* #param string $className Class Name of the Content
* #param int $id Primary Key
*/
public static function Get($className, $id)
{
$content = self::findOne(['object_model' => $className, 'object_id' => $id]);
if ($content != null) {
return $className::findOne(['id' => $id]);
}
return null;
}
/**
* #inheritdoc
*/
public function beforeSave($insert)
{
if ($this->object_model == "" || $this->object_id == "") {
throw new Exception("Could not save content with object_model or object_id!");
}
// Set some default values
if (!$this->archived) {
$this->archived = 0;
}
if (!$this->visibility) {
$this->visibility = self::VISIBILITY_PRIVATE;
}
if (!$this->pinned) {
$this->pinned = 0;
}
if ($insert) {
if ($this->created_by == "") {
$this->created_by = Yii::$app->user->id;
}
}
$this->stream_sort_date = new \yii\db\Expression('NOW()');
if ($this->created_by == "") {
throw new Exception("Could not save content without created_by!");
}
return parent::beforeSave($insert);
}
/**
* #inheritdoc
*/
public function afterSave($insert, $changedAttributes)
{
$contentSource = $this->getPolymorphicRelation();
foreach ($this->notifyUsersOfNewContent as $user) {
$contentSource->follow($user->id);
}
if ($insert && !$contentSource instanceof \humhub\modules\activity\models\Activity) {
if ($this->container !== null) {
$notifyUsers = array_merge($this->notifyUsersOfNewContent, Yii::$app->notification->getFollowers($this));
\humhub\modules\content\notifications\ContentCreated::instance()
->from($this->user)
->about($contentSource)
->sendBulk($notifyUsers);
\humhub\modules\content\activities\ContentCreated::instance()
->about($contentSource)->save();
Yii::$app->live->send(new \humhub\modules\content\live\NewContent([
'sguid' => ($this->container instanceof Space) ? $this->container->guid : null,
'uguid' => ($this->container instanceof User) ? $this->container->guid : null,
'originator' => $this->user->guid,
'contentContainerId' => $this->container->contentContainerRecord->id,
'visibility' => $this->visibility,
'contentId' => $this->id
]));
}
}
return parent::afterSave($insert, $changedAttributes);
}
/**
* #inheritdoc
*/
public function afterDelete()
{
// Try delete the underlying object (Post, Question, Task, ...)
$this->resetPolymorphicRelation();
if ($this->getPolymorphicRelation() !== null) {
$this->getPolymorphicRelation()->delete();
}
parent::afterDelete();
}
/**
* Returns the visibility of the content object
*
* #return Integer
*/
public function getVisibility()
{
return $this->visibility;
}
/**
* Checks if the content visiblity is set to public.
*
* #return boolean
*/
public function isPublic()
{
return $this->visibility == self::VISIBILITY_PUBLIC;
}
/**
* Checks if the content visiblity is set to private.
*
* #return boolean
*/
public function isPrivate()
{
return $this->visibility == self::VISIBILITY_PRIVATE;
}
/**
* Checks if the content object is pinned
*
* #return Boolean
*/
public function isPinned()
{
return ($this->pinned);
}
/**
* Pins the content object
*/
public function pin()
{
$this->pinned = 1;
//This prevents the call of beforesave, and the setting of update_at
$this->updateAttributes(['pinned']);
}
/**
* Unpins the content object
*/
public function unpin()
{
$this->pinned = 0;
$this->updateAttributes(['pinned']);
}
/**
* Checks if the user can pin this content.
* This is only allowed for workspace owner.
*
* #return boolean
*/
public function canPin()
{
if ($this->isArchived()) {
return false;
}
return $this->getContainer()->permissionManager->can(new ManageContent());
}
/**
* Creates a list of pinned content objects of the wall
*
* #return Int
*/
public function countPinnedItems()
{
return Content::find()->where(['content.contentcontainer_id' => $this->contentcontainer_id, 'content.pinned' => 1])->count();
}
/**
* Checks if current content object is archived
*
* #return boolean
*/
public function isArchived()
{
return $this->archived || ($this->getContainer() !== null && $this->getContainer()->isArchived());
}
/**
* Checks if the current user can archive this content.
* The content owner and the workspace admin can archive contents.
*
* #return boolean
*/
public function canArchive()
{
// Disabled on user profiles, there is no stream filter available yet.
if ($this->getContainer() instanceof User) {
return false;
}
return $this->getContainer()->permissionManager->can(new ManageContent());
}
/**
* Archives the content object
*/
public function archive()
{
if ($this->canArchive()) {
if ($this->isPinned()) {
$this->unpin();
}
$this->archived = 1;
if (!$this->save()) {
throw new Exception("Could not archive content!" . print_r($this->getErrors(), 1));
}
}
}
/**
* Unarchives the content object
*/
public function unarchive()
{
if ($this->canArchive()) {
$this->archived = 0;
$this->save();
}
}
/**
* Returns the url of this content.
*
* By default is returns the url of the wall entry.
*
* Optionally it's possible to create an own getUrl method in the underlying
* HActiveRecordContent (e.g. Post) to overwrite this behavior.
* e.g. in case there is no wall entry available for this content.
*
* #since 0.11.1
*/
public function getUrl()
{
if (method_exists($this->getPolymorphicRelation(), 'getUrl')) {
return $this->getPolymorphicRelation()->getUrl();
}
return Url::toRoute(['/content/perma', 'id' => $this->id]);
}
/**
* Sets container (e.g. space or user record) for this content.
*
* #param ContentContainerActiveRecord $container
* #throws Exception
*/
public function setContainer(ContentContainerActiveRecord $container)
{
$this->contentcontainer_id = $container->contentContainerRecord->id;
$this->_container = $container;
}
/**
* Returns the content container (e.g. space or user record) of this content
*
* #return ContentContainerActiveRecord
* #throws Exception
*/
public function getContainer()
{
if ($this->_container != null) {
return $this->_container;
}
if ($this->contentContainer !== null) {
$this->_container = $this->contentContainer->getPolymorphicRelation();
}
return $this->_container;
}
/**
* Relation to ContentContainer model
* Note: this is not a Space or User instance!
*
* #since 1.1
* #return \yii\db\ActiveQuery
*/
public function getContentContainer()
{
return $this->hasOne(ContentContainer::className(), ['id' => 'contentcontainer_id']);
}
/**
* Checks if the given user can edit this content.
*
* A user can edit a content if one of the following conditions are met:
*
* - User is the owner of the content
* - User is system administrator and the content module setting `adminCanEditAllContent` is set to true (default)
* - The user is granted the managePermission set by the model record class
* - The user meets the additional condition implemented by the model records class own `canEdit()` function.
*
* #since 1.1
* #param User $user
* #return bool can edit this content
*/
public function canEdit($user = null)
{
if (Yii::$app->user->isGuest) {
return false;
}
if ($user === null) {
$user = Yii::$app->user->getIdentity();
}
// Only owner can edit his content
if ($user !== null && $this->created_by == $user->id) {
return true;
}
// Global Admin can edit/delete arbitrarily content
if (Yii::$app->getModule('content')->adminCanEditAllContent && $user->isSystemAdmin()) {
return true;
}
/* #var $model ContentActiveRecord */
$model = $this->getPolymorphicRelation();
// Check additional manage permission for the given container
if ($model->hasManagePermission() && $this->getContainer() && $this->getContainer()->getPermissionManager($user)->can($model->getManagePermission())) {
return true;
}
// Check if underlying models canEdit implementation
// ToDo: Implement this as interface
if (method_exists($model, 'canEdit') && $model->canEdit($user)) {
return true;
}
return false;
}
/**
* Checks the given $permission of the current user in the contents content container.
* This is short for `$this->getContainer()->getPermissionManager()->can()`.
*
* #param $permission
* #param array $params
* #param bool $allowCaching
* #see PermissionManager::can()
* #since 1.2.1
* #return bool
*/
public function can($permission, $params = [], $allowCaching = true)
{
return $this->getContainer()->getPermissionManager()->can($permission, $params, $allowCaching);
}
/**
* Checks if user can view this content.
*
* #since 1.1
* #param User $user
* #return boolean can view this content
*/
public function canView($user = null)
{
if (!$user && !Yii::$app->user->isGuest) {
$user = Yii::$app->user->getIdentity();
}
// Check Guest Visibility
if (!$user) {
return $this->checkGuestAccess();
}
// Public visible content
if ($this->isPublic()) {
return true;
}
// Check system admin can see all content module configuration
if ($user->isSystemAdmin() && Yii::$app->getModule('content')->adminCanViewAllContent) {
return true;
}
if ($this->isPrivate() && $this->getContainer()->canAccessPrivateContent($user)) {
return true;
}
return false;
}
/**
* Determines if a guest user is able to read this content.
* This is the case if all of the following conditions are met:
*
* - The content is public
* - The `auth.allowGuestAccess` module setting is enabled
* - The space or profile visibility is set to VISIBILITY_ALL
*
* #return bool
*/
public function checkGuestAccess()
{
if(!$this->isPublic() || !Yii::$app->getModule('user')->settings->get('auth.allowGuestAccess')) {
return false;
}
// Check container visibility for guests
return ($this->container instanceof Space && $this->container->visibility == Space::VISIBILITY_ALL)
|| ($this->container instanceof User && $this->container->visibility == User::VISIBILITY_ALL);
}
/**
* Updates the wall/stream sorting time of this content for "updated at" sorting
*/
public function updateStreamSortTime()
{
$this->updateAttributes(['stream_sort_date' => new \yii\db\Expression('NOW()')]);
}
}
As you can see the first class extends the second one , I'm rather new to php but i'm guessing that's the issue
UPDATE : I tried using the "use class as " and still the same error , I also tried changing the name of the first class to Content1 just to check and still the same .
The problem occours in the second class from the error report
This is a recurring error in a few places in the server I figure I will solve it here and the rest will be the same ,
Many Thanks!
You included file with exacly same class name, so you have 2 class declarations with name Content in this file. Easiest ways to fix it:
Change one of class name
Start using Yii2 autloader, if you need to include something - there's something wrong in your code. You should be able to access
class only by using namespace. There's small conditions you have to
met:
Each class must be under a namespace (e.g. foo\bar\MyClass)
Each class must be saved in an individual file whose path is determined by the following algorithm:
// $className is a fully qualified class name without the leading backslash
$classFile = Yii::getAlias('#' . str_replace('\\', '/', $className) . '.php');
More about Yii2 autloading: Class Autoloading
Related
I recently found this laravel package on github and after installing it, I noticed that the setLocale() function in Translation.php class didn't work as expected. Many issues have been opened about this bug and I started trying to fix it as the maintainer's time was limited due to other open source projects : (Adldap2/Adldap2 and Adldap2/Adldap2-Laravel as stated here.
In Translation.php class, I first changed getLocale() function from
public function getLocale()
{
if ($this->request->hasCookie('locale')) {
return $this->request->cookie('locale');
} else {
return $this->getConfigDefaultLocale();
}
}
to
public function getLocale()
{
if ($this->request->session()->has('locale')) {
return $this->request->session()->get('locale');
} else {
return $this->getConfigDefaultLocale();
}
}
because the comments in the Translation contract specified that sessions were to be used for the getLocale() function.
Then, after inserting some text to translate with the provided helper function {{_t('text')}} in my blade templates, I dumped the result in my localization middleware to see if everything was fine with dd(Translate::getLocale).
I got a 'Session store not set on request.' error. After some googling, I found this thread on Stack Overflow and decided to use the helper function session() and later the Session facade as I found it more convenient.
After these operations, dd(Translate::getLocale) worked fine and I proceeded to modify setLocale() function from
public function setLocale($code = '')
{
$this->locale = $code;
}
to
public function setLocale($code = '')
{
$this->locale = $code;
$this->request->session()->put('locale', $locale);
}
and lastly
public function setLocale($code = '')
{
$this->locale = $code;
session(['locale' => $this->locale]);
}
in order to avoid the 'Session store not set on request' error.
Everything worked correctly.
Despite these actions, the translation still didn't work as expected.
Then, I dumped Translation::getLocale() first in my localization middleware and then in my Translation.php class and I got two different results : 'en' for the Translation.php class and 'fr'(Automatically detected by the middleware).
I also added automatic locale detection to the Translation following this code snippet and tried again with no success.
Finally, I dumped the session variable with dd(Session::all) in the two files and got this from Translation.php class :
array:4 [▼
"locale" => "en"
"_token" => "3FYWDEaPk47ZcqIS2u5KzGmwz7vI0x3G8h9GkNZP"
"_previous" => array:1 [▶]
"_flash" => array:2 [▶]
]
and that from localization middleware :
array:4 [▼
"locale" => "fr"
]
After checking my database where my sessions are stored, I found only one session, so I don't understand why this is happening.
I also checked some blog posts about laravel service container as $app->make() have been used in Translation class constructor, but I'm stuck.
Here are my current Translation.php and localization middleware :
<?php
namespace App\Http\Middleware;
use Closure;
use Carbon\Carbon;
use Session;
use App;
use Config;
use Translation;
use Illuminate\Http\Request;
class Localization
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if ( Session::has('locale')) {
$locale = Session::get('locale', Config::get('app.locale'));
} else {
$locale = substr($request->server('HTTP_ACCEPT_LANGUAGE'), 0, 2);
/*$this->config->get('translation.locales')*/
if ($locale != 'fr' && $locale != 'en') {
$locale = 'en';
}
Session::put('locale', $locale);
}
App::setLocale($locale);
//dd(Session::get('locale'));
Translation::setLocale($locale);
return $next($request);
}
}
<?php
namespace Stevebauman\Translation;
use ErrorException;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\App;
use InvalidArgumentException;
use Stevebauman\Translation\Contracts\Client as ClientInterface;
use Stevebauman\Translation\Contracts\Translation as TranslationInterface;
use UnexpectedValueException;
//use Illuminate\Http\Request;
class Translation implements TranslationInterface
{
/**
* Holds the application .
*
* #var object
*/
protected $app ;
/**
* Holds the application locale.
*
* #var string
*/
protected $locale = '';
/**
* Holds the locale model.
*
* #var Model
*/
protected $localeModel;
/**
* Holds the translation model.
*
* #var Model
*/
protected $translationModel;
/**
* Holds the translation client.
*
* #var ClientInterface
*/
protected $client;
/**
* Holds the current cache instance.
*
* #var \Illuminate\Cache\CacheManager
*/
protected $cache;
/**
* Holds the current config instance.
*
* #var \Illuminate\Config\Repository
*/
protected $config;
/**
* Holds the current request instance.
*
* #var \Illuminate\Http\Request
*/
protected $request;
/**
* The default amount of time (minutes) to store the cached translations.
*
* #var int
*/
private $cacheTime = 30;
/**
* {#inheritdoc}
*/
public function __construct(Application $app)
{
$this->app = $app;
$this->config = $this->app->make('config');
$this->cache = $this->app->make('cache');
$this->request = $this->app->make('request');
$this->localeModel = $this->app->make($this->getConfigLocaleModel());
$this->translationModel = $this->app->make($this->getConfigTranslationModel());
$this->client = $this->app->make($this->getConfigClient());
// Set the default locale to the current application locale
$this->setLocale($this->getConfigDefaultLocale());
// Set the cache time from the configuration
$this->setCacheTime($this->getConfigCacheTime());
}
/**
* {#inheritdoc}
*/
public function translate($text = '', $replacements = [], $toLocale = '', $runOnce = false)
{
try {
// Make sure $text is actually a string and not and object / int
$this->validateText($text);
// Get the default translation text. This will insert the translation
// and the default application locale if they don't
// exist using firstOrCreate
$defaultTranslation = $this->getDefaultTranslation($text);
// If there are replacements inside the array we need to convert them
// into google translate safe placeholders. ex :name to __name__
if (count($replacements) > 0) {
$defaultTranslation->translation = $this->makeTranslationSafePlaceholders($text, $replacements);
}
if ( Session::has('locale')) {
$locale = Session::get('locale');
} else {
$locale = substr($request->server('HTTP_ACCEPT_LANGUAGE'), 0, 2);
/*$this->config->get('translation.locales')*/
if ($locale != 'fr' && $locale != 'en') {
$locale = 'en';
}
Session::put('locale', $locale);
}
App::setLocale($locale);
//dd($locale);
Translation::setLocale($locale);
// If a toLocale has been provided, we're only translating a single string, so
// we won't call the getLocale method as it retrieves and sets the default
// session locale. If it has not been provided, we'll get the
// default locale, and set it on the current session.
if ($toLocale) {
$toLocale = $this->firstOrCreateLocale($toLocale);
} else {
//dd(Session::all());
$toLocale = $this->firstOrCreateLocale($this->getLocale());
}
// Check if translation is requested for default locale.
// If it is default locale we can just return default translation.
if ($defaultTranslation->getAttribute($this->localeModel->getForeignKey()) == $toLocale->getKey()) {
return $this->makeReplacements($defaultTranslation->translation, $replacements);
}
// Since we are not on default translation locale, we will have to
// create (or get first) translation for provided locale where
// parent translation is our default translation.
$translation = $this->firstOrCreateTranslation(
$toLocale,
$defaultTranslation->translation,
$defaultTranslation
);
//dd($this->makeReplacements($translation->translation, $replacements));
return $this->makeReplacements($translation->translation, $replacements);
} catch (\Illuminate\Database\QueryException $e) {
// If foreign key integrity constrains fail, we have a caching issue
if (!$runOnce) {
// If this has not been run before, proceed
// Burst locale cache
$this->removeCacheLocale($toLocale->code);
// Burst translation cache
$this->removeCacheTranslation($this->translationModel->firstOrNew([
$toLocale->getForeignKey() => $toLocale->getKey(),
'translation' => $text,
])
);
// Attempt translation 1 more time
return $this->translate($text, $replacements, $toLocale->code, $runOnce = true);
} else {
// If it has already tried translating once and failed again,
// prevent infinite loops and just return the text
return $text;
}
}
}
/**
* {#inheritdoc}
*/
public function getAppLocale()
{
return $this->config->get('app.locale');
}
/**
* {#inheritdoc}
*/
public function getRoutePrefix()
{
$locale = $this->request->segment($this->getConfigRequestSegment());
$locales = $this->getConfigLocales();
if (is_array($locales) && in_array($locale, array_keys($locales))) {
return $locale;
}
}
/**
* {#inheritdoc}
*/
public function getLocale()
{
//dd($this->request->session()->has('locale'));
/*if ($this->request->session()->has('locale')) {
return $this->request->session()->get('locale');
} else {
return $this->getConfigDefaultLocale();
}*/
/*if (session('locale')) {
return session('locale');
} else {
return $this->getConfigDefaultLocale();
}*/
return Session::get('locale'); //$this->locale;
}
/**
* {#inheritdoc}
*/
public function setLocale($code = '')
{
$this->locale = $code;
/*if(in_array($code, $this->config->get('translation.locales'))){*/
//$this->request->session()->put('locale', $locale);
session(['locale' => $this->locale]);
/* } else {} */
}
/**
* {#inheritdoc}
*/
public function getDefaultTranslation($text)
{
$locale = $this->firstOrCreateLocale($this->getConfigDefaultLocale());
return $this->firstOrCreateTranslation($locale, $text);
}
/**
* Replaces laravel translation placeholders with google
* translate safe placeholders. Ex:.
*
* Converts:
* :name
*
* Into:
* __name__
*
* #param string $text
* #param array $replace
*
* #return mixed
*/
protected function makeTranslationSafePlaceholders($text, array $replace = [])
{
if (count($replace) > 0) {
foreach ($replace as $key => $value) {
// Search for :key
$search = ':'.$key;
// Replace it with __key__
$replace = $this->makeTranslationSafePlaceholder($key);
// Perform the replacements
$text = str_replace($search, $replace, $text);
}
}
return $text;
}
/**
* Makes a placeholder by the specified key.
*
* #param string $key
*
* #return string
*/
protected function makeTranslationSafePlaceholder($key = '')
{
return '___'.strtolower($key).'___';
}
/**
* Make the place-holder replacements on the specified text.
*
* #param string $text
* #param array $replacements
*
* #return string
*/
protected function makeReplacements($text, array $replacements)
{
if (count($replacements) > 0) {
foreach ($replacements as $key => $value) {
$replace = $this->makeTranslationSafePlaceholder($key);
$text = str_ireplace($replace, $value, $text);
}
}
return $text;
}
/**
* Retrieves or creates a locale from the specified code.
*
* #param string $code
*
* #return Model
*/
protected function firstOrCreateLocale($code)
{
$cachedLocale = $this->getCacheLocale($code);
if ($cachedLocale) {
return $cachedLocale;
}
$name = $this->getConfigLocaleByCode($code);
$locale = $this->localeModel->firstOrCreate([
'code' => $code,
'name' => $name,
]);
$this->setCacheLocale($locale);
return $locale;
}
/**
* Creates a translation.
*
* #param Model $locale
* #param string $text
* #param Model $parentTranslation
*
* #return Model
*/
protected function firstOrCreateTranslation(Model $locale, $text, $parentTranslation = null)
{
// We'll check to see if there's a cached translation
// first before we try and hit the database.
$cachedTranslation = $this->getCacheTranslation($locale, $text);
if ($cachedTranslation instanceof Model) {
return $cachedTranslation;
}
// Check if auto translation is enabled. If so we'll run
// the text through google translate and
// save it, then cache it.
if ($parentTranslation && $this->autoTranslateEnabled()) {
$this->client->setSource($parentTranslation->locale->code);
$this->client->setTarget($locale->code);
try {
$text = $this->client->translate($text);
} catch (ErrorException $e) {
// Request to translate failed, set the text
// to the parent translation.
$text = $parentTranslation->translation;
} catch (UnexpectedValueException $e) {
// Looks like something other than text was passed in,
// we'll set the text to the parent translation
// for this exception as well.
$text = $parentTranslation->translation;
}
}
if ($parentTranslation) {
// If a parent translation is given we're looking for it's child translation.
$translation = $this->translationModel->firstOrNew([
$locale->getForeignKey() => $locale->getKey(),
$this->translationModel->getForeignKey() => $parentTranslation->getKey(),
]);
} else {
// Otherwise we're creating the parent translation.
$translation = $this->translationModel->firstOrNew([
$locale->getForeignKey() => $locale->getKey(),
'translation' => $text,
]);
}
if (empty($translation->getAttribute('translation'))) {
// We need to make sure we don't overwrite the translation
// if it exists already in case it was modified.
$translation->setAttribute('translation', $text);
}
if ($translation->isDirty()) {
$translation->save();
}
// Cache the translation so it's retrieved faster next time
$this->setCacheTranslation($translation);
return $translation;
}
/**
* Sets a cache key to the specified locale and text.
*
* #param Model $translation
*/
protected function setCacheTranslation(Model $translation)
{
if ($translation->parent instanceof Model) {
$id = $this->getTranslationCacheId($translation->locale, $translation->parent->translation);
} else {
$id = $this->getTranslationCacheId($translation->locale, $translation->translation);
}
if (!$this->cache->has($id)) {
$this->cache->put($id, $translation, $this->cacheTime);
}
}
/**
* Remove the translation from the cache manually.
*
* #param Model $translation
*/
protected function removeCacheTranslation(Model $translation)
{
$id = $this->getTranslationCacheId($translation->locale, $translation->translation);
if ($this->cache->has($id)) {
$this->cache->forget($id);
}
}
/**
* Retrieves the cached translation from the specified locale
* and text.
*
* #param Model $locale
* #param string $text
*
* #return bool|Model
*/
protected function getCacheTranslation(Model $locale, $text)
{
$id = $this->getTranslationCacheId($locale, $text);
$cachedTranslation = $this->cache->get($id);
if ($cachedTranslation instanceof Model) {
return $cachedTranslation;
}
// Cached translation wasn't found, let's return
// false so we know to generate one.
return false;
}
/**
* Sets a cache key to the specified locale.
*
* #param Model $locale
*/
protected function setCacheLocale(Model $locale)
{
if (!$this->cache->has($locale->code)) {
$id = sprintf('translation.%s', $locale->code);
$this->cache->put($id, $locale, $this->cacheTime);
}
}
/**
* Retrieves a cached locale from the specified locale code.
*
* #param string $code
*
* #return bool
*/
protected function getCacheLocale($code)
{
$id = sprintf('translation.%s', $code);
if ($this->cache->has($id)) {
return $this->cache->get($id);
}
return false;
}
/**
* Remove a locale from the cache.
*
* #param string $code
*/
protected function removeCacheLocale($code)
{
$id = sprintf('translation.%s', $code);
if ($this->cache->has($id)) {
$this->cache->forget($id);
}
}
/**
* Returns a unique translation code by compressing the text
* using a PHP compression function.
*
* #param Model $locale
* #param string $text
*
* #return string
*/
protected function getTranslationCacheId(Model $locale, $text)
{
$compressed = $this->compressString($text);
return sprintf('translation.%s.%s', $locale->code, $compressed);
}
/**
* Returns a the english name of the locale code entered from the config file.
*
* #param string $code
*
* #return string
*/
protected function getConfigLocaleByCode($code)
{
$locales = $this->getConfigLocales();
if (is_array($locales) && array_key_exists($code, $locales)) {
return $locales[$code];
}
return $code;
}
/**
* Sets the time to store the translations and locales in cache.
*
* #param int $time
*/
protected function setCacheTime($time)
{
if (is_numeric($time)) {
$this->cacheTime = $time;
}
}
/**
* Returns the default locale from the configuration.
*
* #return string
*/
protected function getConfigDefaultLocale()
{
return $this->config->get('translation.default_locale', 'en');
}
/**
* Returns the locale model from the configuration.
*
* #return string
*/
protected function getConfigLocaleModel()
{
return $this->config->get('translation.models.locale', Models\Locale::class);
}
/**
* Returns the translation model from the configuration.
*
* #return string
*/
protected function getConfigTranslationModel()
{
return $this->config->get('translation.models.translation', Models\Translation::class);
}
/**
* Returns the translation client from the configuration.
*
* #return string
*/
protected function getConfigClient()
{
return $this->config->get('translation.clients.client', Clients\GoogleTranslate::class);
}
/**
* Returns the request segment to retrieve the locale from.
*
* #return int
*/
protected function getConfigRequestSegment()
{
return $this->config->get('translation.request_segment', 1);
}
/**
* Returns the array of configuration locales.
*
* #return array
*/
protected function getConfigLocales()
{
return $this->config->get('translation.locales');
}
/**
* Returns the cache time set from the configuration file.
*
* #return string|int
*/
protected function getConfigCacheTime()
{
return $this->config->get('translation.cache_time', $this->cacheTime);
}
/**
* Returns the auto translate configuration option.
*
* #return bool
*/
protected function autoTranslateEnabled()
{
return $this->config->get('translation.auto_translate', true);
}
/**
* Calculates the md5 hash of a string.
*
* Used for storing cache keys for translations.
*
* #param $string
*
* #return string
*/
protected function compressString($string)
{
return md5($string);
}
/**
* Validates the inserted text to make sure it's a string.
*
* #param $text
*
* #throws InvalidArgumentException
*
* #return bool
*/
protected function validateText($text)
{
if (!is_string($text)) {
$message = 'Invalid Argument. You must supply a string to be translated.';
throw new InvalidArgumentException($message);
}
return true;
}
}
Thank you!!
I'm trying to "use" a vendor script to connect to feefo api (an online reviews service) but when I try and use the script it gives me this error:
Type error: Argument 1 passed to
BlueBayTravel\Feefo\Feefo::__construct() must be an instance of
GuzzleHttp\Client, null given, called in/Users/webuser1/Projects/_websites/domain.co.uk/plugins/gavinfoster/feefo/components/Feedback.php on line 47
Here is the vendor code I'm using:
/*
* This file is part of Feefo.
*
* (c) Blue Bay Travel <developers#bluebaytravel.co.uk>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace BlueBayTravel\Feefo;
use ArrayAccess;
use Countable;
use Exception;
use GuzzleHttp\Client;
use Illuminate\Contracts\Config\Repository;
use Illuminate\Contracts\Support\Arrayable;
use SimpleXMLElement;
/**
* This is the feefo class.
*
* #author James Brooks <james#bluebaytravel.co.uk>
*/
class Feefo implements Arrayable, ArrayAccess, Countable
{
/**
* The guzzle client.
*
* #var \GuzzleHttp\Client
*/
protected $client;
/**
* The config repository.
*
* #var \Illuminate\Contracts\Config\Repository
*/
protected $config;
/**
* The review items.
*
* #var array
*/
protected $data;
/**
* Create a new feefo instance.
*
* #param \GuzzleHttp\Client $client
* #param \Illuminate\Contracts\Config\Repository $config
*
* #return void
*/
public function __construct(Client $client, Repository $config)
{
$this->client = $client;
$this->config = $config;
}
/**
* Fetch feedback.
*
* #param array|null $params
*
* #return \BlueBayTravel\Feefo\Feefo
*/
public function fetch($params = null)
{
if ($params === null) {
$params['json'] = true;
$params['mode'] = 'both';
}
$params['logon'] = $this->config->get('feefo.logon');
$params['password'] = $this->config->get('feefo.password');
try {
$body = $this->client->get($this->getRequestUrl($params));
return $this->parse((string) $body->getBody());
} catch (Exception $e) {
throw $e; // Re-throw the exception
}
}
/**
* Parses the response.
*
* #param string $data
*
* #return \Illuminate\Support\Collection
*/
protected function parse($data)
{
$xml = new SimpleXMLElement($data);
foreach ((array) $xml as $items) {
if (isset($items->TOTALRESPONSES)) {
continue;
}
foreach ($items as $item) {
$this->data[] = new FeefoItem((array) $item);
}
}
return $this;
}
/**
* Assigns a value to the specified offset.
*
* #param mixed $offset
* #param mixed $value
*
* #return void
*/
public function offsetSet($offset, $value)
{
if (is_null($offset)) {
$this->data[] = $value;
} else {
$this->data[$offset] = $value;
}
}
/**
* Whether or not an offset exists.
*
* #param mixed $offset
*
* #return bool
*/
public function offsetExists($offset)
{
return isset($this->data[$offset]);
}
/**
* Unsets an offset.
*
* #param mixed $offset
*
* #return void
*/
public function offsetUnset($offset)
{
if ($this->offsetExists($offset)) {
unset($this->data[$offset]);
}
}
/**
* Returns the value at specified offset.
*
* #param mixed $offset
*
* #return mixed
*/
public function offsetGet($offset)
{
return $this->offsetExists($offset) ? $this->data[$offset] : null;
}
/**
* Count the number of items in the dataset.
*
* #return int
*/
public function count()
{
return count($this->data);
}
/**
* Get the instance as an array.
*
* #return array
*/
public function toArray()
{
return $this->data;
}
/**
* Returns the Feefo API endpoint.
*
* #param array $params
*
* #return string
*/
protected function getRequestUrl(array $params)
{
$query = http_build_query($params);
return sprintf('%s?%s', $this->config->get('feefo.baseuri'), $query);
}
}
And here is the code I'm using to try and use the fetch() method from the vendor class:
use Cms\Classes\ComponentBase;
use ArrayAccess;
use Countable;
use Exception;
use GuzzleHttp\Client;
use Illuminate\Contracts\Config\Repository;
use Illuminate\Contracts\Support\Arrayable;
use SimpleXMLElement;
use BlueBayTravel\Feefo\Feefo;
class Feedback extends ComponentBase
{
public $client;
public $config;
/**
* Container used for display
* #var BlueBayTravel\Feefo
*/
public $feedback;
public function componentDetails()
{
return [
'name' => 'Feedback Component',
'description' => 'Adds Feefo feedback to the website'
];
}
public function defineProperties()
{
return [];
}
public function onRun()
{
$this->feedback = $this->page['feedback'] = $this->loadFeedback($this->client, $this->config);
}
public function loadFeedback($client, $config)
{
$feefo = new Feefo($client, $config);
$feedback = $feefo->fetch();
return $feedback;
}
}
Won't allow me to call the Fetch() method statically so trying to instantiate and then use:
public function loadFeedback($client, $config)
{
$feefo = new Feefo($client, $config);
$feedback = $feefo->fetch();
return $feedback;
}
I've also tried type hinting the args like this:
public function loadFeedback(Client $client, Repository $config)
{
$feefo = new Feefo($client, $config);
$feedback = $feefo->fetch();
return $feedback;
}
But still I get the exception error above. I'm struggling to understand how to get past this. Any help for a newbie much appreciated :)
Just type hinting the function won't cast it to that object type. You need to properly pass the Guzzle\Client object to your function call.
// Make sure you 'use' the GuzzleClient on top of the class
// or use the Fully Qualified Class Name of the Client
$client = new Client();
$feedback = new Feedback();
// Now we passed the Client object to the function of the feedback class
// which will lead to the constructor of the Feefo class which is
// where your error is coming from.
$loadedFeedback = $feedback->loadFeedback($client);
Don't forget to do the same for the Repository $config from Laravel/Lumen
So, i am new to Symfony and i'm trying to create a functional calendar based application with events rendered from the database using calendar-bundle.
Passing with the documentation i was able to make a relationship between users and events rendered on the calendar but i'm stuck passing particular data, more exactly the user name.
Below is it shown the EventEntity which is responsible for calendar event's details.
<?php
namespace ADesigns\CalendarBundle\Entity;
/**
* Class for holding a calendar event's details.
*
* #author Mike Yudin <mikeyudin#gmail.com>
*/
class EventEntity
{
/**
* #var mixed Unique identifier of this event (optional).
*/
protected $id;
/**
* #var string Title/label of the calendar event.
*/
protected $title;
/**
* #var string URL Relative to current path.
*/
protected $url;
/**
* #var string HTML color code for the bg color of the event label.
*/
protected $bgColor;
/**
* #var string HTML color code for the foregorund color of the event label.
*/
protected $fgColor;
/**
* #var string css class for the event label
*/
protected $cssClass;
/**
* #var \DateTime DateTime object of the event start date/time.
*/
protected $startDatetime;
/**
* #var \DateTime DateTime object of the event end date/time.
*/
protected $endDatetime;
/**
* #var boolean Is this an all day event?
*/
protected $allDay = false;
/**
* #var array Non-standard fields
*/
protected $otherFields = array();
public function __construct($title, \DateTime $startDatetime, \DateTime $endDatetime = null, $allDay = false)
{
$this->title = $title;
$this->startDatetime = $startDatetime;
$this->setAllDay($allDay);
if ($endDatetime === null && $this->allDay === false) {
throw new \InvalidArgumentException("Must specify an event End DateTime if not an all day event.");
}
$this->endDatetime = $endDatetime;
}
/**
* Convert calendar event details to an array
*
* #return array $event
*/
public function toArray()
{
$event = array();
if ($this->id !== null) {
$event['id'] = $this->id;
}
$event['title'] = $this->title;
$event['start'] = $this->startDatetime->format("Y-m-d\TH:i:sP");
if ($this->url !== null) {
$event['url'] = $this->url;
}
if ($this->bgColor !== null) {
$event['backgroundColor'] = $this->bgColor;
$event['borderColor'] = $this->bgColor;
}
if ($this->fgColor !== null) {
$event['textColor'] = $this->fgColor;
}
if ($this->cssClass !== null) {
$event['className'] = $this->cssClass;
}
if ($this->endDatetime !== null) {
$event['end'] = $this->endDatetime->format("Y-m-d\TH:i:sP");
}
$event['allDay'] = $this->allDay;
foreach ($this->otherFields as $field => $value) {
$event[$field] = $value;
}
return $event;
}
public function setId($id)
{
$this->id = $id;
}
public function getId()
{
return $this->id;
}
public function setTitle($title)
{
$this->title = $title;
}
public function getTitle()
{
return $this->title;
}
public function setUrl($url)
{
$this->url = $url;
}
public function getUrl()
{
return $this->url;
}
public function setBgColor($color)
{
$this->bgColor = $color;
}
public function getBgColor()
{
return $this->bgColor;
}
public function setFgColor($color)
{
$this->fgColor = $color;
}
public function getFgColor()
{
return $this->fgColor;
}
public function setCssClass($class)
{
$this->cssClass = $class;
}
public function getCssClass()
{
return $this->cssClass;
}
public function setStartDatetime(\DateTime $start)
{
$this->startDatetime = $start;
}
public function getStartDatetime()
{
return $this->startDatetime;
}
public function setEndDatetime(\DateTime $end)
{
$this->endDatetime = $end;
}
public function getEndDatetime()
{
return $this->endDatetime;
}
public function setAllDay($allDay = false)
{
$this->allDay = (boolean) $allDay;
}
public function getAllDay()
{
return $this->allDay;
}
/**
* #param string $name
* #param string $value
*/
public function addField($name, $value)
{
$this->otherFields[$name] = $value;
}
/**
* #param string $name
*/
public function removeField($name)
{
if (!array_key_exists($name, $this->otherFields)) {
return;
}
unset($this->otherFields[$name]);
}
}
Besides this i have the CalendarEventListener.php which is responsible for data sent to render on the calendar:
<?php
namespace AppBundle\EventListener;
use ADesigns\CalendarBundle\Event\CalendarEvent;
use ADesigns\CalendarBundle\Entity\EventEntity;
use Doctrine\ORM\EntityManager;
class CalendarEventListener
{
private $entityManager;
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function loadEvents(CalendarEvent $calendarEvent)
{
$startDate = $calendarEvent->getStartEventDate();
$endDate = $calendarEvent->getEndEventDate();
// The original request so you can get filters from the calendar
// Use the filter in your query for example
$request = $calendarEvent->getRequest();
$filter = $request->get('filter');
// load events using your custom logic here,
// for instance, retrieving events from a repository
$companyEvents = $this->entityManager->getRepository('AppBundle:companyEvents')
->createQueryBuilder('companyEvents')
->where('companyEvents.startEventDate BETWEEN :startEventDate and :endEventDate')
->setParameter('startEventDate', $startDate->format('Y-m-d H:i:s'))
->setParameter('endEventDate', $endDate->format('Y-m-d H:i:s'))
->getQuery()->getResult();
// $companyEvents and $companyEvent in this example
// represent entities from your database, NOT instances of EventEntity
// within this bundle.
//
// Create EventEntity instances and populate it's properties with data
// from your own entities/database values.
foreach($companyEvents as $companyEvent) {
$eventEntity = new EventEntity($companyEvent->getEventName(),
//
$companyEvent->getStartEventDate(),
$companyEvent->getEndEventDate()
,null, true);
//optional calendar event settings
$eventEntity->setAllDay(true); // default is false, set to true if this is an all day event
$eventEntity->setBgColor('#3366ff'); //set the background color of the event's label
$eventEntity->setFgColor('#FFFFFF'); //set the foreground color of the event's label
$eventEntity->setUrl('http://www.google.com'); // url to send user to when event label is clicked
$eventEntity->setCssClass('my-custom-class'); // a custom class you may want to apply to event labels
//finally, add the event to the CalendarEvent for displaying on the calendar
$calendarEvent->addEvent($eventEntity);
}
}
}
And the companyEvents entity for structuring events:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="companyEvents")
*/
class companyEvents
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* events are created by users
* #ORM\ManyToOne(targetEntity="User", inversedBy="events")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $user;
/**
* #ORM\Column(name="event_name")
*/
private $eventName;
/**
* #ORM\Column(name="event_date", type="datetime")
*/
private $eventDate;
/**
* #ORM\Column(name="startEventDate", type="datetime")
*/
private $startEventDate;
/**
* #ORM\Column(name="endEventDate", type="datetime")
*/
private $endEventDate;
/**
* Set eventName
*
* #param string $eventName
*
* #return companyEvents
*/
public function setEventName($eventName)
{
$this->eventName = $eventName;
return $this;
}
/**
* Get eventName
*
* #return string
*/
public function getEventName()
{
return $this->eventName;
}
/**
* Set eventDate
*
* #param string $eventDate
*
* #return CompanyEvents
*/
public function setEventDate($eventDate)
{
$this->eventDate = $eventDate;
return $this;
}
/**
* Get eventDate
*
* #return string
*/
public function getEventDate()
{
return $this->eventDate;
}
/**
* Set start event date
* #param string $startEventDate
*
* #return companyEvents
*/
public function setStartEventDate($startEventDate)
{
$this->startEventDate = $startEventDate;
return $this;
}
/**
*Get start event date
* #return string
*/
public function getStartEventDate()
{
return $this->startEventDate;
}
/**
* Set start event date
* #param string $endEventDate
*
* #return companyEvents
*/
public function setEndEventDate($endEventDate)
{
$this->endEventDate = $endEventDate;
return $this;
}
/**
*Get start event date
* #return string
*/
public function getEndEventDate()
{
return $this->endEventDate;
}
/**
* set user relationship
* #param string $user_id
*
* #return companyEvents
*/
public function setUser($user)
{
$this->user = $user;
return $this;
}
/**
* #return string
*/
public function getUser()
{
return $this->user;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
}
So, my problem is that instead of getEventName passed here:
$eventEntity = new EventEntity($companyEvent->getEventName(),
$companyEvent->getStartEventDate(),
$companyEvent->getEndEventDate()
,null, true);
i want to pass the particular user name which belongs to the specific event but when i change the getEventName() (WHICH RENDERS THE TITLE OF THE EVENT) with any other function (i have tried to even pass just the user_id from the entity), nothing else is shown in the calendar without dumping any error.
Any hints on resolving this problem will be hardly appreciated :) !
If you want to render the username in the event's title you can change the getEventName method to return the user name:
public function getEventName()
{
return $this->user->getUsername();
}
This way you won't have to change the CalendarEventListener code.
Remember to remove the eventName property and it's setter method from the companyEventsentity. You should also name the entity CamelCased and in the singular, like this CompanyEvent.
I have a User table where userID, username and password are stored and a Role table which contains user role . To link these two tables, I have a table (user_role) which contains userID and roleID. How can I use Zend Auth to authenticate users and use Zend Acl to control user access. This is the database design
You can create a Zend_Auth adapter that works with whatever structure your application has.
Here is an example of an Auth adapter that uses my entity models and mappers to provide the credentials and user data for authentication.
<?php
/**
* Description of Auth_Adapter
*
*/
class Auth_Adapter implements Zend_Auth_Adapter_Interface
{
/**
* The username
*
* #var string
*/
protected $identity = null;
/**
* The password
*
* #var string
*/
protected $credential = null;
/**
* Users database object
*
* #var Model_Mapper_Abstract
*/
protected $usersMapper = null;
/**
* #param string $username
* #param string $password
* #param Model_Mapper_Abstract $userMapper
*/
public function __construct($username, $password, Model_Mapper_Abstract $userMapper = null)
{
if (!is_null($userMapper)) {
$this->setMapper($userMapper);
} else {
$this->usersMapper = new Application_Model_Mapper_User();
}
$this->setIdentity($username);
$this->setCredential($password);
}
/**
* #return \Zend_Auth_Result
*/
public function authenticate()
{
// Fetch user information according to username
$user = $this->getUserObject();
if (is_null($user)) {
return new Zend_Auth_Result(
Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND,
$this->getIdentity(),
array('Invalid username')
);
}
// check whether or not the hash matches using my own password class
$check = Password::comparePassword($this->getCredential(), $user->password);
if (!$check) {
return new Zend_Auth_Result(
Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID,
$this->getIdentity(),
array('Incorrect password')
);
}
// Success!
return new Zend_Auth_Result(
Zend_Auth_Result::SUCCESS,
$this->getIdentity(),
array()
);
}
/**
* #param type $userName
* #return \Auth_Adapter
*/
public function setIdentity($userName)
{
$this->identity = $userName;
return $this;
}
/**
* #param type $password
* #return \Auth_Adapter
*/
public function setCredential($password)
{
$this->credential = $password;
return $this;
}
/**
* #param type $mapper
* #return \Auth_Adapter
*/
public function setMapper($mapper)
{
$this->usersMapper = $mapper;
return $this;
}
/**
* #return object
*/
private function getUserObject()
{
return $this->getMapper()->findOneByColumn('name', $this->getIdentity());
}
/**
* #return object
*/
public function getUser()
{
$object = $this->getUserObject();
$array = array(
'id' => $object->id,
'name' => $object->name,
'role' => $object->role
);
return (object) $array;
}
/**
* #return string
*/
public function getIdentity()
{
return $this->identity;
}
/**
* #return string
*/
public function getCredential()
{
return $this->credential;
}
/**
* #return object Model_Mapper_Abstract
*/
public function getMapper()
{
return $this->usersMapper;
}
}
You could also extend any of the current adapters to provide the functionality you need.
Good Luck!
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.