I have Laravel application on version 5.2 to create dynamic forms which can be emended to any web-page using Iframe, forms were working fine couple of months ago, but now not working on Chrome(latest version) due to following:
this Set-Cookie didn't specify a "SameSite" attribute and was default to samesite=lax and was blocked because it came from the corss-site response which was not the response to a top-level navigtion. The Set-Cookie had to have been set with "SameSite=None" to enable cross-site requests.
Here is the Iframe with all attributes:
<iframe src="https://local.testproject.com/iframe/MSvnBNB9FT4H4m7kNi1OSJtdomsAxW3XnR6KZn1W9dStupbBLjYSfn7txRUNIDCa0UWCR4RbeiWJaMgy6JSDbZXzsFf8C6u32pUD5TiHPqJzxQiLwXXYm8SsUqHqhhoV" sandbox="allow-forms allow-modals allow-popups allow-scripts allow-same-origin allow-top-navigation" style="width: 100%; height: 650px; border: none;"></iframe>
For further see attached screenshot: https://prnt.sc/u6el89
I have researched lot, but did find anything yet. even I customized the core file vendor\symfony\http-foundation\Cookie.php
Following is the customized Cookie.php file:
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien#symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation;
/**
* Represents a cookie.
*
* #author Johannes M. Schmitt <schmittjoh#gmail.com>
*/
class Cookie
{
protected $name;
protected $value;
protected $domain;
protected $expire;
protected $path;
protected $secure;
protected $httpOnly;
protected $sameSite;
/**
* Constructor.
*
* #param string $name The name of the cookie
* #param string $value The value of the cookie
* #param int|string|\DateTimeInterface $expire The time the cookie expires
* #param string $path The path on the server in which the cookie will be available on
* #param string $domain The domain that the cookie is available to
* #param bool $secure Whether the cookie should only be transmitted over a secure HTTPS connection from the client
* #param bool $httpOnly Whether the cookie will be made accessible only through the HTTP protocol
*
* #throws \InvalidArgumentException
*/
public function __construct($name, $value = null, $expire = 0, $path = '/', $domain = null, $secure = false, $httpOnly = true, $sameSite='None')
{
// from PHP source code
if (preg_match("/[=,; \t\r\n\013\014]/", $name)) {
throw new \InvalidArgumentException(sprintf('The cookie name "%s" contains invalid characters.', $name));
}
if (empty($name)) {
throw new \InvalidArgumentException('The cookie name cannot be empty.');
}
// convert expiration time to a Unix timestamp
if ($expire instanceof \DateTimeInterface) {
$expire = $expire->format('U');
} elseif (!is_numeric($expire)) {
$expire = strtotime($expire);
if (false === $expire || -1 === $expire) {
throw new \InvalidArgumentException('The cookie expiration time is not valid.');
}
}
$this->name = $name;
$this->value = $value;
$this->domain = $domain;
$this->expire = $expire;
$this->path = empty($path) ? '/' : $path;
$this->secure = (bool) $secure;
$this->httpOnly = (bool) $httpOnly;
$this->sameSite = $sameSite;
}
/**
* Returns the cookie as a string.
*
* #return string The cookie
*/
public function __toString()
{
$str = urlencode($this->getName()).'=';
if ('' === (string) $this->getValue()) {
$str .= 'deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001);
} else {
$str .= urlencode($this->getValue());
if ($this->getExpiresTime() !== 0) {
$str .= '; expires='.gmdate('D, d-M-Y H:i:s T', $this->getExpiresTime());
}
}
if ($this->path) {
$str .= '; path='.$this->path;
}
if ($this->sameSite) {
$str .= '; SameSite='.$this->sameSite();
}
if ($this->getDomain()) {
$str .= '; domain='.$this->getDomain();
}
if (true === $this->isSecure()) {
$str .= '; secure';
}
if (true === $this->isHttpOnly()) {
$str .= '; httponly';
}
return $str;
}
/**
* Gets the name of the cookie.
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Gets the value of the cookie.
*
* #return string
*/
public function getValue()
{
return $this->value;
}
/**
* Gets the domain that the cookie is available to.
*
* #return string
*/
public function getDomain()
{
return $this->domain;
}
/**
* Gets the time the cookie expires.
*
* #return int
*/
public function getExpiresTime()
{
return $this->expire;
}
/**
* Gets the path on the server in which the cookie will be available on.
*
* #return string
*/
public function getPath()
{
return $this->path;
}
/**
* Checks whether the cookie should only be transmitted over a secure HTTPS connection from the client.
*
* #return bool
*/
public function isSecure()
{
return $this->secure;
}
/**
* Checks whether the cookie will be made accessible only through the HTTP protocol.
*
* #return bool
*/
public function isHttpOnly()
{
return $this->httpOnly;
}
/**
* Whether this cookie is about to be cleared.
*
* #return bool
*/
public function isCleared()
{
return $this->expire < time();
}
/**
* Whether this cookie same site.
*
* #return bool
*/
public function sameSite()
{
return $this->sameSite;
}
}
Also have added in parameter config/session.php:
/*
|--------------------------------------------------------------------------
| Same-Site Cookies
|--------------------------------------------------------------------------
|
| This option determines how your cookies behave when cross-site requests
| take place, and can be used to mitigate CSRF attacks. By default, we
| do not enable this as other CSRF protection services are in place.
|
| Supported: "lax", "strict", "none"
|
*/
'same_site' => 'None'
After that I modified the vendor\laravel\framework\src\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken.php and added new parameter same_site in following method:
protected function addCookieToResponse($request, $response)
{
$config = config('session');
$response->headers->setCookie(
new Cookie(
'XSRF-TOKEN', $request->session()->token(), time() + 60 * $config['lifetime'],
$config['path'], $config['domain'], $config['secure'], false, $config['same_site']
)
);
return $response;
}
Still no luck! I know that modifying core is the not good practice, but I just wanted to make this thing work. please guide how can I achieve this?
Thanks
The same_site attribute was added to laravel in version 5.5:
To use it you must update your laravel app or use simple trick which involves editing path attribute in config/session.php to:
'path' => '/;samesite=none',
And there you go!
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'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
I try to login in my websites using Google API, in local it's working good.
but on server it's given error. error is -
"Got An Error - Hybridauth Library not compatible with installed PECL
OAuth extension. Please disable it."
I had go for get right answer, do r&d and finally I solve my issue.
for it we need to update auth.php (lib. file)
<?php
/**
* HybridAuth
* http://hybridauth.sourceforge.net | http://github.com/hybridauth/hybridauth
* (c) 2009-2015, HybridAuth authors | http://hybridauth.sourceforge.net/licenses.html
*/
/**
* Hybrid_Auth class
*
* Hybrid_Auth class provide a simple way to authenticate users via OpenID and OAuth.
*
* Generally, Hybrid_Auth is the only class you should instanciate and use throughout your application.
*/
class Hybrid_Auth {
public static $version = "2.7.0-dev";
/**
* Configuration array
* #var array
*/
public static $config = array();
/**
* Auth cache
* #var Hybrid_Storage
*/
public static $store = null;
/**
* Error pool
* #var Hybrid_Error
*/
public static $error = null;
/**
* Logger
* #var Hybrid_Logger
*/
public static $logger = null;
/**
* Try to start a new session of none then initialize Hybrid_Auth
*
* Hybrid_Auth constructor will require either a valid config array or
* a path for a configuration file as parameter. To know more please
* refer to the Configuration section:
* http://hybridauth.sourceforge.net/userguide/Configuration.html
*
* #param array $config Configuration array or path to a configratuion file
*/
function __construct($config) {
Hybrid_Auth::initialize($config);
}
/**
* Try to initialize Hybrid_Auth with given $config hash or file
*
* #param array $config Configuration array or path to a configratuion file
* #return void
* #throws Exception
*/
public static function initialize($config) {
if (!is_array($config) && !file_exists($config)) {
throw new Exception("Hybriauth config does not exist on the given path.", 1);
}
if (!is_array($config)) {
$config = include $config;
}
// build some need'd paths
$config["path_base"] = realpath(dirname(__FILE__)) . "/";
$config["path_libraries"] = $config["path_base"] . "thirdparty/";
$config["path_resources"] = $config["path_base"] . "resources/";
$config["path_providers"] = $config["path_base"] . "Providers/";
// reset debug mode
if (!isset($config["debug_mode"])) {
$config["debug_mode"] = false;
$config["debug_file"] = null;
}
# load hybridauth required files, a autoload is on the way...
require_once $config["path_base"] . "Error.php";
//require_once $config["path_base"] . "Exception.php";
require_once $config["path_base"] . "Logger.php";
require_once $config["path_base"] . "Provider_Adapter.php";
require_once $config["path_base"] . "Provider_Model.php";
require_once $config["path_base"] . "Provider_Model_OpenID.php";
require_once $config["path_base"] . "Provider_Model_OAuth1.php";
require_once $config["path_base"] . "Provider_Model_OAuth2.php";
require_once $config["path_base"] . "User.php";
require_once $config["path_base"] . "User_Profile.php";
require_once $config["path_base"] . "User_Contact.php";
require_once $config["path_base"] . "User_Activity.php";
if (!class_exists("Hybrid_Storage", false)) {
require_once $config["path_base"] . "Storage.php";
}
// hash given config
Hybrid_Auth::$config = $config;
// instance of log mng
Hybrid_Auth::$logger = new Hybrid_Logger();
// instance of errors mng
Hybrid_Auth::$error = new Hybrid_Error();
// start session storage mng
Hybrid_Auth::$store = new Hybrid_Storage();
Hybrid_Logger::info("Enter Hybrid_Auth::initialize()");
Hybrid_Logger::info("Hybrid_Auth::initialize(). PHP version: " . PHP_VERSION);
Hybrid_Logger::info("Hybrid_Auth::initialize(). Hybrid_Auth version: " . Hybrid_Auth::$version);
Hybrid_Logger::info("Hybrid_Auth::initialize(). Hybrid_Auth called from: " . Hybrid_Auth::getCurrentUrl());
// PHP Curl extension [http://www.php.net/manual/en/intro.curl.php]
if (!function_exists('curl_init')) {
Hybrid_Logger::error('Hybridauth Library needs the CURL PHP extension.');
throw new Exception('Hybridauth Library needs the CURL PHP extension.');
}
// PHP JSON extension [http://php.net/manual/en/book.json.php]
if (!function_exists('json_decode')) {
Hybrid_Logger::error('Hybridauth Library needs the JSON PHP extension.');
throw new Exception('Hybridauth Library needs the JSON PHP extension.');
}
// session.name
if (session_name() != "PHPSESSID") {
Hybrid_Logger::info('PHP session.name diff from default PHPSESSID. http://php.net/manual/en/session.configuration.php#ini.session.name.');
}
// safe_mode is on
if (ini_get('safe_mode')) {
Hybrid_Logger::info('PHP safe_mode is on. http://php.net/safe-mode.');
}
// open basedir is on
if (ini_get('open_basedir')) {
Hybrid_Logger::info('PHP open_basedir is on. http://php.net/open-basedir.');
}
Hybrid_Logger::debug("Hybrid_Auth initialize. dump used config: ", serialize($config));
Hybrid_Logger::debug("Hybrid_Auth initialize. dump current session: ", Hybrid_Auth::storage()->getSessionData());
Hybrid_Logger::info("Hybrid_Auth initialize: check if any error is stored on the endpoint...");
if (Hybrid_Error::hasError()) {
$m = Hybrid_Error::getErrorMessage();
$c = Hybrid_Error::getErrorCode();
$p = Hybrid_Error::getErrorPrevious();
Hybrid_Logger::error("Hybrid_Auth initialize: A stored Error found, Throw an new Exception and delete it from the store: Error#$c, '$m'");
Hybrid_Error::clearError();
// try to provide the previous if any
// Exception::getPrevious (PHP 5 >= 5.3.0) http://php.net/manual/en/exception.getprevious.php
if (version_compare(PHP_VERSION, '5.3.0', '>=') && ($p instanceof Exception)) {
throw new Exception($m, $c, $p);
} else {
throw new Exception($m, $c);
}
}
Hybrid_Logger::info("Hybrid_Auth initialize: no error found. initialization succeed.");
}
/**
* Hybrid storage system accessor
*
* Users sessions are stored using HybridAuth storage system ( HybridAuth 2.0 handle PHP Session only) and can be accessed directly by
* Hybrid_Auth::storage()->get($key) to retrieves the data for the given key, or calling
* Hybrid_Auth::storage()->set($key, $value) to store the key => $value set.
*
* #return Hybrid_Storage
*/
public static function storage() {
return Hybrid_Auth::$store;
}
/**
* Get hybridauth session data
* #return string|null
*/
function getSessionData() {
return Hybrid_Auth::storage()->getSessionData();
}
/**
* Restore hybridauth session data
*
* #param string $sessiondata Serialized session data
* #retun void
*/
function restoreSessionData($sessiondata = null) {
Hybrid_Auth::storage()->restoreSessionData($sessiondata);
}
/**
* Try to authenticate the user with a given provider.
*
* If the user is already connected we just return and instance of provider adapter,
* ELSE, try to authenticate and authorize the user with the provider.
*
* $params is generally an array with required info in order for this provider and HybridAuth to work,
* like :
* hauth_return_to: URL to call back after authentication is done
* openid_identifier: The OpenID identity provider identifier
* google_service: can be "Users" for Google user accounts service or "Apps" for Google hosted Apps
*
* #param string $providerId ID of the provider
* #param array $params Params
* #return
*/
public static function authenticate($providerId, $params = null) {
Hybrid_Logger::info("Enter Hybrid_Auth::authenticate( $providerId )");
if (!Hybrid_Auth::storage()->get("hauth_session.$providerId.is_logged_in")) {
// if user not connected to $providerId then try setup a new adapter and start the login process for this provider
Hybrid_Logger::info("Hybrid_Auth::authenticate( $providerId ), User not connected to the provider. Try to authenticate..");
$provider_adapter = Hybrid_Auth::setup($providerId, $params);
$provider_adapter->login();
} else {
// else, then return the adapter instance for the given provider
Hybrid_Logger::info("Hybrid_Auth::authenticate( $providerId ), User is already connected to this provider. Return the adapter instance.");
return Hybrid_Auth::getAdapter($providerId);
}
}
/**
* Return the adapter instance for an authenticated provider
*
* #param string $providerId ID of the provider
* #return Hybrid_Provider_Adapter
*/
public static function getAdapter($providerId = null) {
Hybrid_Logger::info("Enter Hybrid_Auth::getAdapter( $providerId )");
return Hybrid_Auth::setup($providerId);
}
/**
* Setup an adapter for a given provider
*
* #param string $providerId ID of the provider
* #param array $params Adapter params
* #return Hybrid_Provider_Adapter
*/
public static function setup($providerId, $params = null) {
Hybrid_Logger::debug("Enter Hybrid_Auth::setup( $providerId )", $params);
if (!$params) {
$params = Hybrid_Auth::storage()->get("hauth_session.$providerId.id_provider_params");
Hybrid_Logger::debug("Hybrid_Auth::setup( $providerId ), no params given. Trying to get the stored for this provider.", $params);
}
if (!$params) {
$params = array();
Hybrid_Logger::info("Hybrid_Auth::setup( $providerId ), no stored params found for this provider. Initialize a new one for new session");
}
if (is_array($params) && !isset($params["hauth_return_to"])) {
$params["hauth_return_to"] = Hybrid_Auth::getCurrentUrl();
Hybrid_Logger::debug("Hybrid_Auth::setup( $providerId ). HybridAuth Callback URL set to: ", $params["hauth_return_to"]);
}
# instantiate a new IDProvider Adapter
$provider = new Hybrid_Provider_Adapter();
$provider->factory($providerId, $params);
return $provider;
}
/**
* Check if the current user is connected to a given provider
*
* #param string $providerId ID of the provider
* #return bool
*/
public static function isConnectedWith($providerId) {
return (bool) Hybrid_Auth::storage()->get("hauth_session.{$providerId}.is_logged_in");
}
/**
* Return array listing all authenticated providers
* #return array
*/
public static function getConnectedProviders() {
$idps = array();
foreach (Hybrid_Auth::$config["providers"] as $idpid => $params) {
if (Hybrid_Auth::isConnectedWith($idpid)) {
$idps[] = $idpid;
}
}
return $idps;
}
/**
* Return array listing all enabled providers as well as a flag if you are connected
*
* <code>
* array(
* 'Facebook' => array(
* 'connected' => true
* )
* )
* </code>
* #return array
*/
public static function getProviders() {
$idps = array();
foreach (Hybrid_Auth::$config["providers"] as $idpid => $params) {
if ($params['enabled']) {
$idps[$idpid] = array('connected' => false);
if (Hybrid_Auth::isConnectedWith($idpid)) {
$idps[$idpid]['connected'] = true;
}
}
}
return $idps;
}
/**
* A generic function to logout all connected provider at once
* #return void
*/
public static function logoutAllProviders() {
$idps = Hybrid_Auth::getConnectedProviders();
foreach ($idps as $idp) {
$adapter = Hybrid_Auth::getAdapter($idp);
$adapter->logout();
}
}
/**
* Utility function, redirect to a given URL with php header or using javascript location.href
*
* #param string $url URL to redirect to
* #param string $mode PHP|JS
*/
public static function redirect($url, $mode = "PHP") {
Hybrid_Logger::info("Enter Hybrid_Auth::redirect( $url, $mode )");
// Ensure session is saved before sending response, see https://github.com/symfony/symfony/pull/12341
if ((PHP_VERSION_ID >= 50400 && PHP_SESSION_ACTIVE === session_status()) || (PHP_VERSION_ID < 50400 && isset($_SESSION) && session_id())) {
session_write_close();
}
if ($mode == "PHP") {
header("Location: $url");
} elseif ($mode == "JS") {
echo '<html>';
echo '<head>';
echo '<script type="text/javascript">';
echo 'function redirect(){ window.top.location.href="' . $url . '"; }';
echo '</script>';
echo '</head>';
echo '<body onload="redirect()">';
echo 'Redirecting, please wait...';
echo '</body>';
echo '</html>';
}
die();
}
/**
* Utility function, return the current url
*
* #param bool $request_uri true to get $_SERVER['REQUEST_URI'], false for $_SERVER['PHP_SELF']
* #return string
*/
public static function getCurrentUrl($request_uri = true) {
if (php_sapi_name() == 'cli') {
return '';
}
$protocol = 'http://';
if ((isset($_SERVER['HTTPS']) && ( $_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1 ))
|| (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'))
{
$protocol = 'https://';
}
$url = $protocol . $_SERVER['HTTP_HOST'];
if ($request_uri) {
$url .= $_SERVER['REQUEST_URI'];
} else {
$url .= $_SERVER['PHP_SELF'];
}
// return current url
return $url;
}
}
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?
I just started with OOP programming in PHP and I have made a cookie class.
With doing that i have got a few questions unanswered
is my class correct?
how do I use it properly in my page? ( lets think i want to see how many times the visitor visited my website before and output the result for the user )
I already tested it after loging in and using this code:
$cookie = new Cookie();
$cookie->store();
print_r($_COOKIE);
(I had a result thrown back but I don't know if its the good result)
Bellow you can find my Cookie class.
<?php
class Cookie {
/* cookie $id */
private $id = false;
/* cookie life $time */
private $time = false;
/* cookie $domain */
private $domain = false;
/* cookie $path */
private $path = false;
/* cookie $secure (true is https only) */
private $secure = false;
public function __construct ($id, $time = 3600, $path = false, $domain = false, $secure = false) {
$this->id = $id;
$this->time = $time;
$this->path = $path;
$this->domain = $domain;
$this->secure = $secure;
}
public function store() {
foreach ($this->parameters as $parameter => $validator) {
setcookie($this->id . "[" . $parameter . "]", $validator->getValue(), time() + $this->time, $this->path, $this->domain, $this->secure, true);
}
}
public function restore() {
if (isset($_COOKIE[$this->id])) {
foreach ($_COOKIE[$this->id] as $parameter => $value) {
$this->{$parameter} = $value;
}
}
}
public function destroy() {
$this->time = -1;
}
}
?>
I hope someone can give me a good example! thanks for the help in advance!
This code should do the most frequent tasks you'll need to manipulate cookies.
Don't get confused by reading the getter and setter methods - they're used to access the private variables defined in the class.
Have in mind this class is used per cookie and you need to have a new instance for every new cookie you'll operate over.
Below the class I've added an example how to use the class.
<?php
/**
* Cookie manager.
*/
class Cookie
{
/**
* Cookie name - the name of the cookie.
* #var bool
*/
private $name = false;
/**
* Cookie value
* #var string
*/
private $value = "";
/**
* Cookie life time
* #var DateTime
*/
private $time;
/**
* Cookie domain
* #var bool
*/
private $domain = false;
/**
* Cookie path
* #var bool
*/
private $path = false;
/**
* Cookie secure
* #var bool
*/
private $secure = false;
/**
* Constructor
*/
public function __construct() { }
/**
* Create or Update cookie.
*/
public function create() {
return setcookie($this->name, $this->getValue(), $this->getTime(), $this->getPath(), $this->getDomain(), $this->getSecure(), true);
}
/**
* Return a cookie
* #return mixed
*/
public function get(){
return $_COOKIE[$this->getName()];
}
/**
* Delete cookie.
* #return bool
*/
public function delete(){
return setcookie($this->name, '', time() - 3600, $this->getPath(), $this->getDomain(), $this->getSecure(), true);
}
/**
* #param $domain
*/
public function setDomain($domain) {
$this->domain = $domain;
}
/**
* #return bool
*/
public function getDomain() {
return $this->domain;
}
/**
* #param $id
*/
public function setName($id) {
$this->name = $id;
}
/**
* #return bool
*/
public function getName() {
return $this->name;
}
/**
* #param $path
*/
public function setPath($path) {
$this->path = $path;
}
/**
* #return bool
*/
public function getPath() {
return $this->path;
}
/**
* #param $secure
*/
public function setSecure($secure) {
$this->secure = $secure;
}
/**
* #return bool
*/
public function getSecure() {
return $this->secure;
}
/**
* #param $time
*/
public function setTime($time) {
// Create a date
$date = new DateTime();
// Modify it (+1hours; +1days; +20years; -2days etc)
$date->modify($time);
// Store the date in UNIX timestamp.
$this->time = $date->getTimestamp();
}
/**
* #return bool|int
*/
public function getTime() {
return $this->time;
}
/**
* #param string $value
*/
public function setValue($value) {
$this->value = $value;
}
/**
* #return string
*/
public function getValue() {
return $this->value;
}
}
/**
* Create a cookie with the name "myCookieName" and value "testing cookie value"
*/
$cookie = new Cookie();
// Set cookie name
$cookie->setName('myCookieName');
// Set cookie value
$cookie->setValue("testing cookie value");
// Set cookie expiration time
$cookie->setTime("+1 hour");
// Create the cookie
$cookie->create();
// Get the cookie value.
print_r($cookie->get());
// Delete the cookie.
//$cookie->delete();
?>
P.S. I've commented the $cookie->delete(); on purpose so that you can see the content of print_r($cookie->get()).
Edit:
Question: Where does the code go to see if the cookie is set?
Answer:
You should check what does $_COOKIE do in the php documentation.
Basically the server sends headers to the client's browser which stores the cookies on the client's computer. When the client initializes a connection to the server it passes the cookies with the request.
Question: Where goes the $cookie->delete();
Answer:
There isn't a direct way to delete cookies. So in order to do that you need to create a cookie with the same name and expiration time which is in the past. When you do that the cookie is removed from the client's browser.