From 0218d16335cd4b873c3edd59fbcc110306d87e71 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Tue, 26 Jun 2018 22:31:04 +0200 Subject: [PATCH 01/65] Lock abstraction (like the Cache) - adding interface - adding seperate drivers - moving Lock to the Core package --- src/Core/Lock.php | 97 ++++++++++++ src/Core/Lock/DatabaseLockDriver.php | 83 ++++++++++ src/Core/Lock/ILockDriver.php | 38 +++++ src/Core/Lock/MemcacheLockDriver.php | 86 +++++++++++ src/Core/Lock/SemaphoreLockDriver.php | 82 ++++++++++ src/Core/Worker.php | 17 +-- src/Protocol/OStatus.php | 5 +- src/Util/Lock.php | 211 -------------------------- 8 files changed, 396 insertions(+), 223 deletions(-) create mode 100644 src/Core/Lock.php create mode 100644 src/Core/Lock/DatabaseLockDriver.php create mode 100644 src/Core/Lock/ILockDriver.php create mode 100644 src/Core/Lock/MemcacheLockDriver.php create mode 100644 src/Core/Lock/SemaphoreLockDriver.php delete mode 100644 src/Util/Lock.php diff --git a/src/Core/Lock.php b/src/Core/Lock.php new file mode 100644 index 0000000000..9e02d14fcb --- /dev/null +++ b/src/Core/Lock.php @@ -0,0 +1,97 @@ +=')) { + self::$driver = new Lock\SemaphoreLockDriver(); + } elseif (Config::get('system', 'cache_driver', 'database') == 'memcache') { + self::$driver = new Lock\MemcacheLockDriver(); + } else { + self::$driver = new Lock\DatabaseLockDriver(); + } + } + } + + /** + * Returns the current cache driver + * + * @return Lock\ILockDriver; + */ + private static function getDriver() + { + if (self::$driver === null) { + self::init(); + } + + return self::$driver; + } + + /** + * @brief Acquires a lock for a given name + * + * @param string $key Name of the lock + * @param integer $timeout Seconds until we give up + * + * @return boolean Was the lock successful? + */ + public static function acquireLock($key, $timeout = 120) + { + return self::getDriver()->acquireLock($key, $timeout); + } + + /** + * @brief Releases a lock if it was set by us + * + * @param string $key Name of the lock + * @return mixed + */ + public static function releaseLock($key) + { + return self::getDriver()->releaseLock($key); + } + + /** + * @brief Releases all lock that were set by us + * @return void + */ + public static function releaseAll() + { + self::getDriver()->releaseAll(); + } +} diff --git a/src/Core/Lock/DatabaseLockDriver.php b/src/Core/Lock/DatabaseLockDriver.php new file mode 100644 index 0000000000..8761a1479e --- /dev/null +++ b/src/Core/Lock/DatabaseLockDriver.php @@ -0,0 +1,83 @@ + $key]); + + if (DBM::is_result($lock)) { + if ($lock['locked']) { + // When the process id isn't used anymore, we can safely claim the lock for us. + if (!posix_kill($lock['pid'], 0)) { + $lock['locked'] = false; + } + // We want to lock something that was already locked by us? So we got the lock. + if ($lock['pid'] == getmypid()) { + $got_lock = true; + } + } + if (!$lock['locked']) { + dba::update('locks', ['locked' => true, 'pid' => getmypid()], ['name' => $key]); + $got_lock = true; + } + } elseif (!DBM::is_result($lock)) { + dba::insert('locks', ['name' => $key, 'locked' => true, 'pid' => getmypid()]); + $got_lock = true; + } + + dba::unlock(); + + if (!$got_lock && ($timeout > 0)) { + usleep(rand(100000, 2000000)); + } + } while (!$got_lock && ((time() - $start) < $timeout)); + + return $got_lock; + } + + /** + * @brief Removes a lock if it was set by us + * + * @param string $key Name of the lock + * + * @return mixed + */ + public function releaseLock($key) + { + dba::update('locks', ['locked' => false, 'pid' => 0], ['name' => $key, 'pid' => getmypid()]); + + return; + } + + /** + * @brief Removes all lock that were set by us + * + * @return void + */ + public function releaseAll() + { + dba::update('locks', ['locked' => false, 'pid' => 0], ['pid' => getmypid()]); + } +} diff --git a/src/Core/Lock/ILockDriver.php b/src/Core/Lock/ILockDriver.php new file mode 100644 index 0000000000..b066361be6 --- /dev/null +++ b/src/Core/Lock/ILockDriver.php @@ -0,0 +1,38 @@ + + */ +interface ILockDriver +{ + /** + * + * @brief Acquires a lock for a given name + * + * @param string $key The Name of the lock + * @param integer $timeout Seconds until we give up + * + * @return boolean Was the lock successful? + */ + public function acquireLock($key, $timeout = 120); + + /** + * @brief Releases a lock if it was set by us + * + * @param string $key Name of the lock + * + * @return mixed + */ + public function releaseLock($key); + + /** + * @brief Releases all lock that were set by us + * + * @return void + */ + public function releaseAll(); +} \ No newline at end of file diff --git a/src/Core/Lock/MemcacheLockDriver.php b/src/Core/Lock/MemcacheLockDriver.php new file mode 100644 index 0000000000..1796d81366 --- /dev/null +++ b/src/Core/Lock/MemcacheLockDriver.php @@ -0,0 +1,86 @@ +get_hostname() . ";lock:" . $key; + + do { + // We only lock to be sure that nothing happens at exactly the same time + dba::lock('locks'); + $lock = Cache::get($cachekey); + + if (!is_bool($lock)) { + $pid = (int)$lock; + + // When the process id isn't used anymore, we can safely claim the lock for us. + // Or we do want to lock something that was already locked by us. + if (!posix_kill($pid, 0) || ($pid == getmypid())) { + $lock = false; + } + } + if (is_bool($lock)) { + Cache::set($cachekey, getmypid(), 300); + $got_lock = true; + } + + dba::unlock(); + + if (!$got_lock && ($timeout > 0)) { + usleep(rand(10000, 200000)); + } + } while (!$got_lock && ((time() - $start) < $timeout)); + + return $got_lock; + } + + /** + * @brief Removes a lock if it was set by us + * + * @param string $key Name of the lock + * + * @return mixed + */ + public function releaseLock($key) + { + $cachekey = get_app()->get_hostname() . ";lock:" . $key; + $lock = Cache::get($cachekey); + + if (!is_bool($lock)) { + if ((int)$lock == getmypid()) { + Cache::delete($cachekey); + } + } + + return; + } + + /** + * @brief Removes all lock that were set by us + * + * @return void + */ + public function releaseAll() + { + // We cannot delete all cache entries, but this doesn't matter with memcache + return; + } +} \ No newline at end of file diff --git a/src/Core/Lock/SemaphoreLockDriver.php b/src/Core/Lock/SemaphoreLockDriver.php new file mode 100644 index 0000000000..93911a3d10 --- /dev/null +++ b/src/Core/Lock/SemaphoreLockDriver.php @@ -0,0 +1,82 @@ +=')) { + self::$semaphore[$key] = sem_get(self::semaphoreKey($key)); + if (self::$semaphore[$key]) { + return sem_acquire(self::$semaphore[$key], ($timeout == 0)); + } + } + } + + /** + * @brief Removes a lock if it was set by us + * + * @param string $key Name of the lock + * + * @return mixed + */ + public function releaseLock($key) + { + if (function_exists('sem_get') && version_compare(PHP_VERSION, '5.6.1', '>=')) { + if (empty(self::$semaphore[$key])) { + return false; + } else { + $success = @sem_release(self::$semaphore[$key]); + unset(self::$semaphore[$key]); + return $success; + } + } + } + + /** + * @brief Removes all lock that were set by us + * + * @return void + */ + public function releaseAll() + { + // not needed/supported + return; + } +} \ No newline at end of file diff --git a/src/Core/Worker.php b/src/Core/Worker.php index c965e05830..b8a9021d0f 100644 --- a/src/Core/Worker.php +++ b/src/Core/Worker.php @@ -10,7 +10,6 @@ use Friendica\Core\System; use Friendica\Database\DBM; use Friendica\Model\Process; use Friendica\Util\DateTimeFormat; -use Friendica\Util\Lock; use Friendica\Util\Network; use dba; @@ -108,16 +107,16 @@ class Worker } // If possible we will fetch new jobs for this worker - if (!$refetched && Lock::set('worker_process', 0)) { + if (!$refetched && Lock::acquireLock('worker_process', 0)) { $stamp = (float)microtime(true); $refetched = self::findWorkerProcesses($passing_slow); self::$db_duration += (microtime(true) - $stamp); - Lock::remove('worker_process'); + Lock::releaseLock('worker_process'); } } // To avoid the quitting of multiple workers only one worker at a time will execute the check - if (Lock::set('worker', 0)) { + if (Lock::acquireLock('worker', 0)) { $stamp = (float)microtime(true); // Count active workers and compare them with a maximum value that depends on the load if (self::tooMuchWorkers()) { @@ -130,7 +129,7 @@ class Worker logger('Memory limit reached, quitting.', LOGGER_DEBUG); return; } - Lock::remove('worker'); + Lock::releaseLock('worker'); self::$db_duration += (microtime(true) - $stamp); } @@ -883,7 +882,7 @@ class Worker dba::close($r); $stamp = (float)microtime(true); - if (!Lock::set('worker_process')) { + if (!Lock::acquireLock('worker_process')) { return false; } self::$lock_duration = (microtime(true) - $stamp); @@ -892,7 +891,7 @@ class Worker $found = self::findWorkerProcesses($passing_slow); self::$db_duration += (microtime(true) - $stamp); - Lock::remove('worker_process'); + Lock::releaseLock('worker_process'); if ($found) { $r = dba::select('workerqueue', [], ['pid' => getmypid(), 'done' => false]); @@ -1097,13 +1096,13 @@ class Worker } // If there is a lock then we don't have to check for too much worker - if (!Lock::set('worker', 0)) { + if (!Lock::acquireLock('worker', 0)) { return true; } // If there are already enough workers running, don't fork another one $quit = self::tooMuchWorkers(); - Lock::remove('worker'); + Lock::releaseLock('worker'); if ($quit) { return true; diff --git a/src/Protocol/OStatus.php b/src/Protocol/OStatus.php index 2c826221e7..69975c5753 100644 --- a/src/Protocol/OStatus.php +++ b/src/Protocol/OStatus.php @@ -19,7 +19,6 @@ use Friendica\Model\User; use Friendica\Network\Probe; use Friendica\Object\Image; use Friendica\Util\DateTimeFormat; -use Friendica\Util\Lock; use Friendica\Util\Network; use Friendica\Util\XML; use dba; @@ -513,9 +512,9 @@ class OStatus logger("Item with uri ".$item["uri"]." is from a blocked contact.", LOGGER_DEBUG); } else { // We are having duplicated entries. Hopefully this solves it. - if (Lock::set('ostatus_process_item_insert')) { + if (Lock::acquireLock('ostatus_process_item_insert')) { $ret = Item::insert($item); - Lock::remove('ostatus_process_item_insert'); + Lock::releaseLock('ostatus_process_item_insert'); logger("Item with uri ".$item["uri"]." for user ".$importer["uid"].' stored. Return value: '.$ret); } else { $ret = Item::insert($item); diff --git a/src/Util/Lock.php b/src/Util/Lock.php deleted file mode 100644 index eba264ad93..0000000000 --- a/src/Util/Lock.php +++ /dev/null @@ -1,211 +0,0 @@ -connect($memcache_host, $memcache_port)) { - return false; - } - - return $memcache; - } - - /** - * @brief Creates a semaphore key - * - * @param string $fn_name Name of the lock - * - * @return ressource the semaphore key - */ - private static function semaphoreKey($fn_name) - { - $temp = get_temppath(); - - $file = $temp.'/'.$fn_name.'.sem'; - - if (!file_exists($file)) { - file_put_contents($file, $fn_name); - } - - return ftok($file, 'f'); - } - - /** - * @brief Sets a lock for a given name - * - * @param string $fn_name Name of the lock - * @param integer $timeout Seconds until we give up - * - * @return boolean Was the lock successful? - */ - public static function set($fn_name, $timeout = 120) - { - $got_lock = false; - $start = time(); - - // The second parameter for "sem_acquire" doesn't exist before 5.6.1 - if (function_exists('sem_get') && version_compare(PHP_VERSION, '5.6.1', '>=')) { - self::$semaphore[$fn_name] = sem_get(self::semaphoreKey($fn_name)); - if (self::$semaphore[$fn_name]) { - return sem_acquire(self::$semaphore[$fn_name], ($timeout == 0)); - } - } - - $memcache = self::connectMemcache(); - if (is_object($memcache)) { - $cachekey = get_app()->get_hostname().";lock:".$fn_name; - - do { - // We only lock to be sure that nothing happens at exactly the same time - dba::lock('locks'); - $lock = $memcache->get($cachekey); - - if (!is_bool($lock)) { - $pid = (int)$lock; - - // When the process id isn't used anymore, we can safely claim the lock for us. - // Or we do want to lock something that was already locked by us. - if (!posix_kill($pid, 0) || ($pid == getmypid())) { - $lock = false; - } - } - if (is_bool($lock)) { - $memcache->set($cachekey, getmypid(), MEMCACHE_COMPRESSED, 300); - $got_lock = true; - } - - dba::unlock(); - - if (!$got_lock && ($timeout > 0)) { - usleep(rand(10000, 200000)); - } - } while (!$got_lock && ((time() - $start) < $timeout)); - - return $got_lock; - } - - do { - dba::lock('locks'); - $lock = dba::selectFirst('locks', ['locked', 'pid'], ['name' => $fn_name]); - - if (DBM::is_result($lock)) { - if ($lock['locked']) { - // When the process id isn't used anymore, we can safely claim the lock for us. - if (!posix_kill($lock['pid'], 0)) { - $lock['locked'] = false; - } - // We want to lock something that was already locked by us? So we got the lock. - if ($lock['pid'] == getmypid()) { - $got_lock = true; - } - } - if (!$lock['locked']) { - dba::update('locks', ['locked' => true, 'pid' => getmypid()], ['name' => $fn_name]); - $got_lock = true; - } - } elseif (!DBM::is_result($lock)) { - dba::insert('locks', ['name' => $fn_name, 'locked' => true, 'pid' => getmypid()]); - $got_lock = true; - } - - dba::unlock(); - - if (!$got_lock && ($timeout > 0)) { - usleep(rand(100000, 2000000)); - } - } while (!$got_lock && ((time() - $start) < $timeout)); - - return $got_lock; - } - - /** - * @brief Removes a lock if it was set by us - * - * @param string $fn_name Name of the lock - * @return mixed - */ - public static function remove($fn_name) - { - if (function_exists('sem_get') && version_compare(PHP_VERSION, '5.6.1', '>=')) { - if (empty(self::$semaphore[$fn_name])) { - return false; - } else { - $success = @sem_release(self::$semaphore[$fn_name]); - unset(self::$semaphore[$fn_name]); - return $success; - } - } - - $memcache = self::connectMemcache(); - if (is_object($memcache)) { - $cachekey = get_app()->get_hostname().";lock:".$fn_name; - $lock = $memcache->get($cachekey); - - if (!is_bool($lock)) { - if ((int)$lock == getmypid()) { - $memcache->delete($cachekey); - } - } - return; - } - - dba::update('locks', ['locked' => false, 'pid' => 0], ['name' => $fn_name, 'pid' => getmypid()]); - return; - } - - /** - * @brief Removes all lock that were set by us - * @return void - */ - public static function removeAll() - { - $memcache = self::connectMemcache(); - if (is_object($memcache)) { - // We cannot delete all cache entries, but this doesn't matter with memcache - return; - } - - dba::update('locks', ['locked' => false, 'pid' => 0], ['pid' => getmypid()]); - return; - } -} From a57e6cfa1b6c1e7c75698b2e804b917edff671e9 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Tue, 26 Jun 2018 23:28:07 +0200 Subject: [PATCH 02/65] Moved Lock.php back to Utils --- src/Core/Worker.php | 1 + src/Protocol/OStatus.php | 1 + src/{Core => Util}/Lock.php | 7 ++++++- src/{Core => Util}/Lock/DatabaseLockDriver.php | 2 +- src/{Core => Util}/Lock/ILockDriver.php | 5 ++++- src/{Core => Util}/Lock/MemcacheLockDriver.php | 2 +- src/{Core => Util}/Lock/SemaphoreLockDriver.php | 2 +- 7 files changed, 15 insertions(+), 5 deletions(-) rename src/{Core => Util}/Lock.php (96%) rename src/{Core => Util}/Lock/DatabaseLockDriver.php (98%) rename src/{Core => Util}/Lock/ILockDriver.php (91%) rename src/{Core => Util}/Lock/MemcacheLockDriver.php (98%) rename src/{Core => Util}/Lock/SemaphoreLockDriver.php (98%) diff --git a/src/Core/Worker.php b/src/Core/Worker.php index b8a9021d0f..0e8835a156 100644 --- a/src/Core/Worker.php +++ b/src/Core/Worker.php @@ -11,6 +11,7 @@ use Friendica\Database\DBM; use Friendica\Model\Process; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; +use Friendica\Util\Lock; use dba; require_once 'include/dba.php'; diff --git a/src/Protocol/OStatus.php b/src/Protocol/OStatus.php index 69975c5753..a1223b7b68 100644 --- a/src/Protocol/OStatus.php +++ b/src/Protocol/OStatus.php @@ -19,6 +19,7 @@ use Friendica\Model\User; use Friendica\Network\Probe; use Friendica\Object\Image; use Friendica\Util\DateTimeFormat; +use Friendica\Util\Lock; use Friendica\Util\Network; use Friendica\Util\XML; use dba; diff --git a/src/Core/Lock.php b/src/Util/Lock.php similarity index 96% rename from src/Core/Lock.php rename to src/Util/Lock.php index 9e02d14fcb..95341b4b66 100644 --- a/src/Core/Lock.php +++ b/src/Util/Lock.php @@ -10,7 +10,7 @@ namespace Friendica\Util; */ use Friendica\Core\Config; -use Friendica\Core\Lock; +use Friendica\Util\Lock; require_once 'include/dba.php'; @@ -94,4 +94,9 @@ class Lock { self::getDriver()->releaseAll(); } + + public static function isLocked($key) + { + + } } diff --git a/src/Core/Lock/DatabaseLockDriver.php b/src/Util/Lock/DatabaseLockDriver.php similarity index 98% rename from src/Core/Lock/DatabaseLockDriver.php rename to src/Util/Lock/DatabaseLockDriver.php index 8761a1479e..b2e8f50279 100644 --- a/src/Core/Lock/DatabaseLockDriver.php +++ b/src/Util/Lock/DatabaseLockDriver.php @@ -1,6 +1,6 @@ Date: Tue, 26 Jun 2018 23:33:02 +0200 Subject: [PATCH 03/65] Bugfixing ILockDriver (forgot isLocked) --- src/Util/Lock/ILockDriver.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Util/Lock/ILockDriver.php b/src/Util/Lock/ILockDriver.php index 6b8a08cb04..97052b35af 100644 --- a/src/Util/Lock/ILockDriver.php +++ b/src/Util/Lock/ILockDriver.php @@ -35,7 +35,4 @@ interface ILockDriver * @return void */ public function releaseAll(); - - - public function isLocked(); } \ No newline at end of file From dd085ae59226d4d25fa7b2ab0ec18edaab54d286 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Tue, 26 Jun 2018 23:42:26 +0200 Subject: [PATCH 04/65] minor changes --- src/Core/Worker.php | 2 +- src/Util/Lock.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Core/Worker.php b/src/Core/Worker.php index 0e8835a156..ef7873fcd4 100644 --- a/src/Core/Worker.php +++ b/src/Core/Worker.php @@ -10,8 +10,8 @@ use Friendica\Core\System; use Friendica\Database\DBM; use Friendica\Model\Process; use Friendica\Util\DateTimeFormat; -use Friendica\Util\Network; use Friendica\Util\Lock; +use Friendica\Util\Network; use dba; require_once 'include/dba.php'; diff --git a/src/Util/Lock.php b/src/Util/Lock.php index 95341b4b66..76e29826cb 100644 --- a/src/Util/Lock.php +++ b/src/Util/Lock.php @@ -1,11 +1,11 @@ Date: Tue, 26 Jun 2018 23:43:43 +0200 Subject: [PATCH 05/65] minor changes --- src/Util/Lock.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Util/Lock.php b/src/Util/Lock.php index 76e29826cb..b6a4a97f18 100644 --- a/src/Util/Lock.php +++ b/src/Util/Lock.php @@ -94,9 +94,4 @@ class Lock { self::getDriver()->releaseAll(); } - - public static function isLocked($key) - { - - } } From acf6a5cb9ede84dabedda3e0925776c83efd9337 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Tue, 26 Jun 2018 23:44:30 +0200 Subject: [PATCH 06/65] minor changes --- src/Util/Lock/ILockDriver.php | 2 +- src/Util/Lock/MemcacheLockDriver.php | 2 +- src/Util/Lock/SemaphoreLockDriver.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Util/Lock/ILockDriver.php b/src/Util/Lock/ILockDriver.php index 97052b35af..7f5a359946 100644 --- a/src/Util/Lock/ILockDriver.php +++ b/src/Util/Lock/ILockDriver.php @@ -35,4 +35,4 @@ interface ILockDriver * @return void */ public function releaseAll(); -} \ No newline at end of file +} diff --git a/src/Util/Lock/MemcacheLockDriver.php b/src/Util/Lock/MemcacheLockDriver.php index 9a3ceb4645..d0789a95c4 100644 --- a/src/Util/Lock/MemcacheLockDriver.php +++ b/src/Util/Lock/MemcacheLockDriver.php @@ -83,4 +83,4 @@ class MemcacheLockDriver implements ILockDriver // We cannot delete all cache entries, but this doesn't matter with memcache return; } -} \ No newline at end of file +} diff --git a/src/Util/Lock/SemaphoreLockDriver.php b/src/Util/Lock/SemaphoreLockDriver.php index 3adf1ff37c..1cd3af1411 100644 --- a/src/Util/Lock/SemaphoreLockDriver.php +++ b/src/Util/Lock/SemaphoreLockDriver.php @@ -79,4 +79,4 @@ class SemaphoreLockDriver implements ILockDriver // not needed/supported return; } -} \ No newline at end of file +} From 3f7e4f5bb67c67586423d9e1105ce274b83767c3 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Thu, 28 Jun 2018 22:57:17 +0200 Subject: [PATCH 07/65] redesign of locking & caching - New Factory "CacheDriverFactory" for Cache and Locks - Adding Redis/Memcached Locking - Moved Lock to Core - other improvements --- src/Core/Cache.php | 27 +--- src/Core/Cache/CacheDriverFactory.php | 48 ++++++ src/Core/Lock.php | 145 ++++++++++++++++++ src/Core/Lock/AbstractLockDriver.php | 57 +++++++ .../Lock/CacheLockDriver.php} | 51 +++--- .../Lock/DatabaseLockDriver.php | 20 ++- src/{Util => Core}/Lock/ILockDriver.php | 10 +- src/Core/Lock/SemaphoreLockDriver.php | 68 ++++++++ src/Core/Worker.php | 2 +- src/Protocol/OStatus.php | 2 +- src/Util/Lock.php | 97 ------------ src/Util/Lock/SemaphoreLockDriver.php | 82 ---------- 12 files changed, 369 insertions(+), 240 deletions(-) create mode 100644 src/Core/Cache/CacheDriverFactory.php create mode 100644 src/Core/Lock.php create mode 100644 src/Core/Lock/AbstractLockDriver.php rename src/{Util/Lock/MemcacheLockDriver.php => Core/Lock/CacheLockDriver.php} (61%) rename src/{Util => Core}/Lock/DatabaseLockDriver.php (79%) rename src/{Util => Core}/Lock/ILockDriver.php (72%) create mode 100644 src/Core/Lock/SemaphoreLockDriver.php delete mode 100644 src/Util/Lock.php delete mode 100644 src/Util/Lock/SemaphoreLockDriver.php diff --git a/src/Core/Cache.php b/src/Core/Cache.php index 4202db325c..cc77d9bfd0 100644 --- a/src/Core/Cache.php +++ b/src/Core/Cache.php @@ -4,8 +4,7 @@ */ namespace Friendica\Core; -use Friendica\Core\Cache; -use Friendica\Core\Config; +use Friendica\Core\Cache\CacheDriverFactory; /** * @brief Class for storing data for a short time @@ -24,31 +23,13 @@ class Cache extends \Friendica\BaseObject /** * @var Cache\ICacheDriver */ - static $driver = null; + private static $driver = null; public static function init() { - switch(Config::get('system', 'cache_driver', 'database')) { - case 'memcache': - $memcache_host = Config::get('system', 'memcache_host', '127.0.0.1'); - $memcache_port = Config::get('system', 'memcache_port', 11211); + $driver_name = Config::get('system', 'cache_driver', 'database'); - self::$driver = new Cache\MemcacheCacheDriver($memcache_host, $memcache_port); - break; - case 'memcached': - $memcached_hosts = Config::get('system', 'memcached_hosts', [['127.0.0.1', 11211]]); - - self::$driver = new Cache\MemcachedCacheDriver($memcached_hosts); - break; - case 'redis': - $redis_host = Config::get('system', 'redis_host', '127.0.0.1'); - $redis_port = Config::get('system', 'redis_port', 6379); - - self::$driver = new Cache\RedisCacheDriver($redis_host, $redis_port); - break; - default: - self::$driver = new Cache\DatabaseCacheDriver(); - } + self::$driver = CacheDriverFactory::create($driver_name); } /** diff --git a/src/Core/Cache/CacheDriverFactory.php b/src/Core/Cache/CacheDriverFactory.php new file mode 100644 index 0000000000..d15b8e9858 --- /dev/null +++ b/src/Core/Cache/CacheDriverFactory.php @@ -0,0 +1,48 @@ +getMessage()); + } + } + + // 2. Try to use Cache Locking (don't use the DB-Cache Locking because it works different!) + $cache_driver = Config::get('system', 'cache_driver', 'database'); + if ($cache_driver != 'database') { + try { + $lock_driver = CacheDriverFactory::create($cache_driver); + self::$driver = new Lock\CacheLockDriver($lock_driver); + return; + } catch (\Exception $exception) { + logger('Using Cache driver for locking failed: ' . $exception->getMessage()); + } + } + + // 3. Use Database Locking as a Fallback + self::$driver = new Lock\DatabaseLockDriver(); + } + + /** + * Returns the current cache driver + * + * @return Lock\ILockDriver; + */ + private static function getDriver() + { + if (self::$driver === null) { + self::init(); + } + + return self::$driver; + } + + /** + * @brief Acquires a lock for a given name + * + * @param string $key Name of the lock + * @param integer $timeout Seconds until we give up + * + * @return boolean Was the lock successful? + */ + public static function acquireLock($key, $timeout = 120) + { + return self::getDriver()->acquireLock($key, $timeout); + } + + /** + * @brief Releases a lock if it was set by us + * + * @param string $key Name of the lock + * @return mixed + */ + public static function releaseLock($key) + { + return self::getDriver()->releaseLock($key); + } + + /** + * @brief Releases all lock that were set by us + * @return void + */ + public static function releaseAll() + { + self::getDriver()->releaseAll(); + } +} diff --git a/src/Core/Lock/AbstractLockDriver.php b/src/Core/Lock/AbstractLockDriver.php new file mode 100644 index 0000000000..15820c3782 --- /dev/null +++ b/src/Core/Lock/AbstractLockDriver.php @@ -0,0 +1,57 @@ +acquireLock[$key]); + } + + /** + * @brief Mark a locally acquired lock + * + * @param string $key The Name of the lock + */ + protected function markAcquire(string $key) { + $this->acquiredLocks[$key] = true; + } + + /** + * @brief Mark a release of a locally acquired lock + * + * @param string $key The Name of the lock + */ + protected function markRelease(string $key) { + unset($this->acquiredLocks[$key]); + } + + /** + * @brief Releases all lock that were set by us + * + * @return void + */ + public function releaseAll() { + foreach ($this->acquiredLocks as $acquiredLock) { + $this->releaseLock($acquiredLock); + } + } +} diff --git a/src/Util/Lock/MemcacheLockDriver.php b/src/Core/Lock/CacheLockDriver.php similarity index 61% rename from src/Util/Lock/MemcacheLockDriver.php rename to src/Core/Lock/CacheLockDriver.php index d0789a95c4..0adca140d1 100644 --- a/src/Util/Lock/MemcacheLockDriver.php +++ b/src/Core/Lock/CacheLockDriver.php @@ -1,12 +1,26 @@ cache = $cache; + } + /** * * @brief Sets a lock for a given name @@ -16,7 +30,7 @@ class MemcacheLockDriver implements ILockDriver * * @return boolean Was the lock successful? */ - public function acquireLock($key, $timeout = 120) + public function acquireLock(string $key, int $timeout = 120) { $got_lock = false; $start = time(); @@ -24,9 +38,7 @@ class MemcacheLockDriver implements ILockDriver $cachekey = get_app()->get_hostname() . ";lock:" . $key; do { - // We only lock to be sure that nothing happens at exactly the same time - dba::lock('locks'); - $lock = Cache::get($cachekey); + $lock = $this->cache->get($cachekey); if (!is_bool($lock)) { $pid = (int)$lock; @@ -38,17 +50,17 @@ class MemcacheLockDriver implements ILockDriver } } if (is_bool($lock)) { - Cache::set($cachekey, getmypid(), 300); + $this->cache->set($cachekey, getmypid(), 300); $got_lock = true; } - dba::unlock(); - if (!$got_lock && ($timeout > 0)) { usleep(rand(10000, 200000)); } } while (!$got_lock && ((time() - $start) < $timeout)); + $this->markAcquire($key); + return $got_lock; } @@ -59,28 +71,19 @@ class MemcacheLockDriver implements ILockDriver * * @return mixed */ - public function releaseLock($key) + public function releaseLock(string $key) { $cachekey = get_app()->get_hostname() . ";lock:" . $key; - $lock = Cache::get($cachekey); + $lock = $this->cache->get($cachekey); if (!is_bool($lock)) { if ((int)$lock == getmypid()) { - Cache::delete($cachekey); + $this->cache->delete($cachekey); } } - return; - } + $this->markRelease($key); - /** - * @brief Removes all lock that were set by us - * - * @return void - */ - public function releaseAll() - { - // We cannot delete all cache entries, but this doesn't matter with memcache return; } } diff --git a/src/Util/Lock/DatabaseLockDriver.php b/src/Core/Lock/DatabaseLockDriver.php similarity index 79% rename from src/Util/Lock/DatabaseLockDriver.php rename to src/Core/Lock/DatabaseLockDriver.php index b2e8f50279..f9878340cf 100644 --- a/src/Util/Lock/DatabaseLockDriver.php +++ b/src/Core/Lock/DatabaseLockDriver.php @@ -1,6 +1,6 @@ true, 'pid' => getmypid()], ['name' => $key]); $got_lock = true; } - } elseif (!DBM::is_result($lock)) { + } else { dba::insert('locks', ['name' => $key, 'locked' => true, 'pid' => getmypid()]); $got_lock = true; } @@ -54,6 +54,8 @@ class DatabaseLockDriver implements ILockDriver } } while (!$got_lock && ((time() - $start) < $timeout)); + $this->markAcquire($key); + return $got_lock; } @@ -64,9 +66,11 @@ class DatabaseLockDriver implements ILockDriver * * @return mixed */ - public function releaseLock($key) + public function releaseLock(string $key) { - dba::update('locks', ['locked' => false, 'pid' => 0], ['name' => $key, 'pid' => getmypid()]); + dba::delete('locks', ['locked' => false, 'pid' => 0], ['name' => $key, 'pid' => getmypid()]); + + $this->releaseLock($key); return; } @@ -78,6 +82,8 @@ class DatabaseLockDriver implements ILockDriver */ public function releaseAll() { - dba::update('locks', ['locked' => false, 'pid' => 0], ['pid' => getmypid()]); + dba::delete('locks', ['locked' => false, 'pid' => 0], ['pid' => getmypid()]); + + $this->acquiredLocks = []; } } diff --git a/src/Util/Lock/ILockDriver.php b/src/Core/Lock/ILockDriver.php similarity index 72% rename from src/Util/Lock/ILockDriver.php rename to src/Core/Lock/ILockDriver.php index 7f5a359946..39e4ba8e89 100644 --- a/src/Util/Lock/ILockDriver.php +++ b/src/Core/Lock/ILockDriver.php @@ -1,6 +1,6 @@ acquiredLocks[$key] = sem_get(self::semaphoreKey($key)); + if ($this->acquiredLocks[$key]) { + return sem_acquire($this->acquiredLocks[$key], ($timeout == 0)); + } + } + + /** + * @brief Removes a lock if it was set by us + * + * @param string $key Name of the lock + * + * @return mixed + */ + public function releaseLock(string $key) + { + if (empty($this->acquiredLocks[$key])) { + return false; + } else { + $success = @sem_release($this->acquiredLocks[$key]); + unset($this->acquiredLocks[$key]); + return $success; + } + } +} diff --git a/src/Core/Worker.php b/src/Core/Worker.php index ef7873fcd4..cbf2ae8bd9 100644 --- a/src/Core/Worker.php +++ b/src/Core/Worker.php @@ -7,10 +7,10 @@ namespace Friendica\Core; use Friendica\Core\Addon; use Friendica\Core\Config; use Friendica\Core\System; +use Friendica\Core\Lock; use Friendica\Database\DBM; use Friendica\Model\Process; use Friendica\Util\DateTimeFormat; -use Friendica\Util\Lock; use Friendica\Util\Network; use dba; diff --git a/src/Protocol/OStatus.php b/src/Protocol/OStatus.php index a1223b7b68..288cbfed1b 100644 --- a/src/Protocol/OStatus.php +++ b/src/Protocol/OStatus.php @@ -9,6 +9,7 @@ use Friendica\Content\Text\HTML; use Friendica\Core\Cache; use Friendica\Core\Config; use Friendica\Core\L10n; +use Friendica\Core\Lock; use Friendica\Core\System; use Friendica\Database\DBM; use Friendica\Model\Contact; @@ -19,7 +20,6 @@ use Friendica\Model\User; use Friendica\Network\Probe; use Friendica\Object\Image; use Friendica\Util\DateTimeFormat; -use Friendica\Util\Lock; use Friendica\Util\Network; use Friendica\Util\XML; use dba; diff --git a/src/Util/Lock.php b/src/Util/Lock.php deleted file mode 100644 index b6a4a97f18..0000000000 --- a/src/Util/Lock.php +++ /dev/null @@ -1,97 +0,0 @@ -=')) { - self::$driver = new Lock\SemaphoreLockDriver(); - } elseif (Config::get('system', 'cache_driver', 'database') == 'memcache') { - self::$driver = new Lock\MemcacheLockDriver(); - } else { - self::$driver = new Lock\DatabaseLockDriver(); - } - } - } - - /** - * Returns the current cache driver - * - * @return Lock\ILockDriver; - */ - private static function getDriver() - { - if (self::$driver === null) { - self::init(); - } - - return self::$driver; - } - - /** - * @brief Acquires a lock for a given name - * - * @param string $key Name of the lock - * @param integer $timeout Seconds until we give up - * - * @return boolean Was the lock successful? - */ - public static function acquireLock($key, $timeout = 120) - { - return self::getDriver()->acquireLock($key, $timeout); - } - - /** - * @brief Releases a lock if it was set by us - * - * @param string $key Name of the lock - * @return mixed - */ - public static function releaseLock($key) - { - return self::getDriver()->releaseLock($key); - } - - /** - * @brief Releases all lock that were set by us - * @return void - */ - public static function releaseAll() - { - self::getDriver()->releaseAll(); - } -} diff --git a/src/Util/Lock/SemaphoreLockDriver.php b/src/Util/Lock/SemaphoreLockDriver.php deleted file mode 100644 index 1cd3af1411..0000000000 --- a/src/Util/Lock/SemaphoreLockDriver.php +++ /dev/null @@ -1,82 +0,0 @@ -=')) { - self::$semaphore[$key] = sem_get(self::semaphoreKey($key)); - if (self::$semaphore[$key]) { - return sem_acquire(self::$semaphore[$key], ($timeout == 0)); - } - } - } - - /** - * @brief Removes a lock if it was set by us - * - * @param string $key Name of the lock - * - * @return mixed - */ - public function releaseLock($key) - { - if (function_exists('sem_get') && version_compare(PHP_VERSION, '5.6.1', '>=')) { - if (empty(self::$semaphore[$key])) { - return false; - } else { - $success = @sem_release(self::$semaphore[$key]); - unset(self::$semaphore[$key]); - return $success; - } - } - } - - /** - * @brief Removes all lock that were set by us - * - * @return void - */ - public function releaseAll() - { - // not needed/supported - return; - } -} From 4b7be15560e3e9623d806a86bd999a513e281d4f Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Thu, 28 Jun 2018 23:02:00 +0200 Subject: [PATCH 08/65] Deleting return-types of methods --- src/Core/Cache/CacheDriverFactory.php | 2 +- src/Core/Lock/AbstractLockDriver.php | 2 +- src/Core/Lock/SemaphoreLockDriver.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Core/Cache/CacheDriverFactory.php b/src/Core/Cache/CacheDriverFactory.php index d15b8e9858..e9ff4331d7 100644 --- a/src/Core/Cache/CacheDriverFactory.php +++ b/src/Core/Cache/CacheDriverFactory.php @@ -20,7 +20,7 @@ class CacheDriverFactory * @return ICacheDriver The instance of the CacheDriver * @throws \Exception The exception if something went wrong during the CacheDriver creation */ - public static function create(string $driver) : ICacheDriver { + public static function create(string $driver) { switch ($driver) { case 'memcache': diff --git a/src/Core/Lock/AbstractLockDriver.php b/src/Core/Lock/AbstractLockDriver.php index 15820c3782..4c2bfaec95 100644 --- a/src/Core/Lock/AbstractLockDriver.php +++ b/src/Core/Lock/AbstractLockDriver.php @@ -22,7 +22,7 @@ abstract class AbstractLockDriver implements ILockDriver * @param string key The Name of the lock * @return bool Returns true if the lock is set */ - protected function hasAcquiredLock(string $key): bool { + protected function hasAcquiredLock(string $key) { return isset($this->acquireLock[$key]); } diff --git a/src/Core/Lock/SemaphoreLockDriver.php b/src/Core/Lock/SemaphoreLockDriver.php index 84965a1643..4eb30b9d02 100644 --- a/src/Core/Lock/SemaphoreLockDriver.php +++ b/src/Core/Lock/SemaphoreLockDriver.php @@ -18,7 +18,7 @@ class SemaphoreLockDriver extends AbstractLockDriver * * @return integer the semaphore key */ - private static function semaphoreKey(string $key): int + private static function semaphoreKey(string $key) { $temp = get_temppath(); From ad5ee75159f86010ad0acdf3475eb49f3b9f1192 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Thu, 28 Jun 2018 23:06:14 +0200 Subject: [PATCH 09/65] Deleting parameter-types of methods (lack of support in PHP 5.6) --- src/Core/Cache/CacheDriverFactory.php | 2 +- src/Core/Lock/AbstractLockDriver.php | 6 +++--- src/Core/Lock/CacheLockDriver.php | 4 ++-- src/Core/Lock/DatabaseLockDriver.php | 4 ++-- src/Core/Lock/ILockDriver.php | 4 ++-- src/Core/Lock/SemaphoreLockDriver.php | 6 +++--- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Core/Cache/CacheDriverFactory.php b/src/Core/Cache/CacheDriverFactory.php index e9ff4331d7..45cc17a52f 100644 --- a/src/Core/Cache/CacheDriverFactory.php +++ b/src/Core/Cache/CacheDriverFactory.php @@ -20,7 +20,7 @@ class CacheDriverFactory * @return ICacheDriver The instance of the CacheDriver * @throws \Exception The exception if something went wrong during the CacheDriver creation */ - public static function create(string $driver) { + public static function create($driver) { switch ($driver) { case 'memcache': diff --git a/src/Core/Lock/AbstractLockDriver.php b/src/Core/Lock/AbstractLockDriver.php index 4c2bfaec95..bcce26129c 100644 --- a/src/Core/Lock/AbstractLockDriver.php +++ b/src/Core/Lock/AbstractLockDriver.php @@ -22,7 +22,7 @@ abstract class AbstractLockDriver implements ILockDriver * @param string key The Name of the lock * @return bool Returns true if the lock is set */ - protected function hasAcquiredLock(string $key) { + protected function hasAcquiredLock($key) { return isset($this->acquireLock[$key]); } @@ -31,7 +31,7 @@ abstract class AbstractLockDriver implements ILockDriver * * @param string $key The Name of the lock */ - protected function markAcquire(string $key) { + protected function markAcquire($key) { $this->acquiredLocks[$key] = true; } @@ -40,7 +40,7 @@ abstract class AbstractLockDriver implements ILockDriver * * @param string $key The Name of the lock */ - protected function markRelease(string $key) { + protected function markRelease($key) { unset($this->acquiredLocks[$key]); } diff --git a/src/Core/Lock/CacheLockDriver.php b/src/Core/Lock/CacheLockDriver.php index 0adca140d1..1bb768bd0f 100644 --- a/src/Core/Lock/CacheLockDriver.php +++ b/src/Core/Lock/CacheLockDriver.php @@ -30,7 +30,7 @@ class CacheLockDriver extends AbstractLockDriver * * @return boolean Was the lock successful? */ - public function acquireLock(string $key, int $timeout = 120) + public function acquireLock($key, $timeout = 120) { $got_lock = false; $start = time(); @@ -71,7 +71,7 @@ class CacheLockDriver extends AbstractLockDriver * * @return mixed */ - public function releaseLock(string $key) + public function releaseLock($key) { $cachekey = get_app()->get_hostname() . ";lock:" . $key; $lock = $this->cache->get($cachekey); diff --git a/src/Core/Lock/DatabaseLockDriver.php b/src/Core/Lock/DatabaseLockDriver.php index f9878340cf..9b415753fc 100644 --- a/src/Core/Lock/DatabaseLockDriver.php +++ b/src/Core/Lock/DatabaseLockDriver.php @@ -18,7 +18,7 @@ class DatabaseLockDriver extends AbstractLockDriver * * @return boolean Was the lock successful? */ - public function acquireLock(string $key, int $timeout = 120) + public function acquireLock($key, $timeout = 120) { $got_lock = false; $start = time(); @@ -66,7 +66,7 @@ class DatabaseLockDriver extends AbstractLockDriver * * @return mixed */ - public function releaseLock(string $key) + public function releaseLock($key) { dba::delete('locks', ['locked' => false, 'pid' => 0], ['name' => $key, 'pid' => getmypid()]); diff --git a/src/Core/Lock/ILockDriver.php b/src/Core/Lock/ILockDriver.php index 39e4ba8e89..8744d757f1 100644 --- a/src/Core/Lock/ILockDriver.php +++ b/src/Core/Lock/ILockDriver.php @@ -18,7 +18,7 @@ interface ILockDriver * * @return boolean Was the lock successful? */ - public function acquireLock(string $key, int $timeout = 120); + public function acquireLock($key, $timeout = 120); /** * @brief Releases a lock if it was set by us @@ -27,7 +27,7 @@ interface ILockDriver * * @return void */ - public function releaseLock(string $key); + public function releaseLock($key); /** * @brief Releases all lock that were set by us diff --git a/src/Core/Lock/SemaphoreLockDriver.php b/src/Core/Lock/SemaphoreLockDriver.php index 4eb30b9d02..39e3e1d32c 100644 --- a/src/Core/Lock/SemaphoreLockDriver.php +++ b/src/Core/Lock/SemaphoreLockDriver.php @@ -18,7 +18,7 @@ class SemaphoreLockDriver extends AbstractLockDriver * * @return integer the semaphore key */ - private static function semaphoreKey(string $key) + private static function semaphoreKey($key) { $temp = get_temppath(); @@ -40,7 +40,7 @@ class SemaphoreLockDriver extends AbstractLockDriver * * @return boolean Was the lock successful? */ - public function acquireLock(string $key, int $timeout = 120) + public function acquireLock($key, $timeout = 120) { $this->acquiredLocks[$key] = sem_get(self::semaphoreKey($key)); if ($this->acquiredLocks[$key]) { @@ -55,7 +55,7 @@ class SemaphoreLockDriver extends AbstractLockDriver * * @return mixed */ - public function releaseLock(string $key) + public function releaseLock($key) { if (empty($this->acquiredLocks[$key])) { return false; From 28741c8366e9ab341729db22540dc32effa1fe98 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Mon, 2 Jul 2018 07:23:47 -0400 Subject: [PATCH 10/65] Remove startup() function - Enable notice errors --- boot.php | 30 ------------------------------ src/App.php | 5 ++++- 2 files changed, 4 insertions(+), 31 deletions(-) diff --git a/boot.php b/boot.php index a4588b3f73..e876d25a3f 100644 --- a/boot.php +++ b/boot.php @@ -499,36 +499,6 @@ if (!defined("SIGTERM")) { if (!defined('CURLE_OPERATION_TIMEDOUT')) { define('CURLE_OPERATION_TIMEDOUT', CURLE_OPERATION_TIMEOUTED); } -/** - * Reverse the effect of magic_quotes_gpc if it is enabled. - * Please disable magic_quotes_gpc so we don't have to do this. - * See http://php.net/manual/en/security.magicquotes.disabling.php - */ -function startup() -{ - error_reporting(E_ERROR | E_WARNING | E_PARSE); - - set_time_limit(0); - - // This has to be quite large to deal with embedded private photos - ini_set('pcre.backtrack_limit', 500000); - - if (get_magic_quotes_gpc()) { - $process = [&$_GET, &$_POST, &$_COOKIE, &$_REQUEST]; - while (list($key, $val) = each($process)) { - foreach ($val as $k => $v) { - unset($process[$key][$k]); - if (is_array($v)) { - $process[$key][stripslashes($k)] = $v; - $process[] = &$process[$key][stripslashes($k)]; - } else { - $process[$key][stripslashes($k)] = stripslashes($v); - } - } - } - unset($process); - } -} /** * @brief Retrieve the App structure diff --git a/src/App.php b/src/App.php index f5626761e5..22678f53ee 100644 --- a/src/App.php +++ b/src/App.php @@ -181,7 +181,10 @@ class App $this->process_id = uniqid('log', true); - startup(); + set_time_limit(0); + + // This has to be quite large to deal with embedded private photos + ini_set('pcre.backtrack_limit', 500000); $this->scheme = 'http'; From 6776c4e3f97e03d396ba4973cf5e444a64ce1a3d Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 1 Jul 2018 00:15:11 -0400 Subject: [PATCH 11/65] Fix some undefined variable/index notices in tests --- include/api.php | 40 ++++++++++++++++++++++------------------ include/security.php | 4 ++-- src/Core/System.php | 1 + src/Network/Probe.php | 2 ++ tests/ApiTest.php | 3 ++- 5 files changed, 29 insertions(+), 21 deletions(-) diff --git a/include/api.php b/include/api.php index 32fe6c651d..6d38be95b7 100644 --- a/include/api.php +++ b/include/api.php @@ -90,11 +90,15 @@ function api_source() } // Support for known clients that doesn't send a source name - if (strpos($_SERVER['HTTP_USER_AGENT'], "Twidere") !== false) { - return "Twidere"; + if (!empty($_SERVER['HTTP_USER_AGENT'])) { + if(strpos($_SERVER['HTTP_USER_AGENT'], "Twidere") !== false) { + return "Twidere"; + } + + logger("Unrecognized user-agent ".$_SERVER['HTTP_USER_AGENT'], LOGGER_DEBUG); } - logger("Unrecognized user-agent ".$_SERVER['HTTP_USER_AGENT'], LOGGER_DEBUG); + logger("Empty user-agent", LOGGER_DEBUG); return "api"; } @@ -193,8 +197,8 @@ function api_login(App $a) throw new UnauthorizedException("This API requires login"); } - $user = $_SERVER['PHP_AUTH_USER']; - $password = $_SERVER['PHP_AUTH_PW']; + $user = defaults($_SERVER, 'PHP_AUTH_USER', ''); + $password = defaults($_SERVER, 'PHP_AUTH_PW', ''); // allow "user@server" login (but ignore 'server' part) $at = strstr($user, "@", true); @@ -258,7 +262,7 @@ function api_check_method($method) if ($method == "*") { return true; } - return (strpos($method, $_SERVER['REQUEST_METHOD']) !== false); + return (stripos($method, defaults($_SERVER, 'REQUEST_METHOD', 'GET')) !== false); } /** @@ -298,7 +302,7 @@ function api_call(App $a) //unset($_SERVER['PHP_AUTH_USER']); /// @TODO should be "true ==[=] $info['auth']", if you miss only one = character, you assign a variable (only with ==). Let's make all this even. - if ($info['auth'] === true && api_user() === false) { + if (!empty($info['auth']) && api_user() === false) { api_login($a); } @@ -659,7 +663,7 @@ function api_get_user(App $a, $contact_id = null) 'geo_enabled' => false, 'verified' => false, 'statuses_count' => 0, - 'lang' => '', + 'language' => '', 'contributors_enabled' => false, 'is_translator' => false, 'is_translation_enabled' => false, @@ -740,7 +744,7 @@ function api_get_user(App $a, $contact_id = null) 'geo_enabled' => false, 'verified' => true, 'statuses_count' => intval($countitems), - 'lang' => '', + 'language' => '', 'contributors_enabled' => false, 'is_translator' => false, 'is_translation_enabled' => false, @@ -773,13 +777,13 @@ function api_get_user(App $a, $contact_id = null) $link_color = PConfig::get($ret['uid'], 'frio', 'link_color'); $bgcolor = PConfig::get($ret['uid'], 'frio', 'background_color'); } - if (!$nav_bg) { + if (empty($nav_bg)) { $nav_bg = "#708fa0"; } - if (!$link_color) { + if (empty($link_color)) { $link_color = "#6fdbe8"; } - if (!$bgcolor) { + if (empty($bgcolor)) { $bgcolor = "#ededed"; } @@ -801,12 +805,12 @@ function api_get_user(App $a, $contact_id = null) */ function api_item_get_user(App $a, $item) { - $status_user = api_get_user($a, $item["author-id"]); + $status_user = api_get_user($a, defaults($item, 'author-id', null)); - $status_user["protected"] = $item["private"]; + $status_user["protected"] = defaults($item, 'private', 0); - if ($item['thr-parent'] == $item['uri']) { - $owner_user = api_get_user($a, $item["owner-id"]); + if (defaults($item, 'thr-parent', '') == defaults($item, 'uri', '')) { + $owner_user = api_get_user($a, defaults($item, 'author-id', null)); } else { $owner_user = $status_user; } @@ -1308,7 +1312,7 @@ function api_status_show($type) 'favorited' => $lastwall['starred'] ? true : false, 'retweeted' => false, 'possibly_sensitive' => false, - 'lang' => "", + 'language' => "", 'statusnet_html' => $converted["html"], 'statusnet_conversation_id' => $lastwall['parent'], 'external_url' => System::baseUrl() . "/display/" . $lastwall['guid'], @@ -2205,7 +2209,7 @@ function api_favorites_create_destroy($type) // for versioned api. /// @TODO We need a better global soluton $action_argv_id = 2; - if ($a->argv[1] == "1.1") { + if (count($a->argv) > 1 && $a->argv[1] == "1.1") { $action_argv_id = 3; } diff --git a/include/security.php b/include/security.php index e8a03ad0fe..dbba09172e 100644 --- a/include/security.php +++ b/include/security.php @@ -41,7 +41,7 @@ function new_cookie($time, $user = []) if ($user) { $value = json_encode(["uid" => $user["uid"], "hash" => cookie_hash($user), - "ip" => $_SERVER['REMOTE_ADDR']]); + "ip" => defaults($_SERVER, 'REMOTE_ADDR', '0.0.0.0')]); } else { $value = ""; } @@ -70,7 +70,7 @@ function authenticate_success($user_record, $login_initial = false, $interactive $_SESSION['page_flags'] = $user_record['page-flags']; $_SESSION['my_url'] = System::baseUrl() . '/profile/' . $user_record['nickname']; $_SESSION['my_address'] = $user_record['nickname'] . '@' . substr(System::baseUrl(), strpos(System::baseUrl(), '://') + 3); - $_SESSION['addr'] = $_SERVER['REMOTE_ADDR']; + $_SESSION['addr'] = defaults($_SERVER, 'REMOTE_ADDR', '0.0.0.0'); $a->user = $user_record; diff --git a/src/Core/System.php b/src/Core/System.php index ded781da83..abc39e5a2a 100644 --- a/src/Core/System.php +++ b/src/Core/System.php @@ -72,6 +72,7 @@ class System extends BaseObject } } elseif (!in_array($func['function'], $ignore)) { $callstack[] = $func['function']; + $func['class'] = ''; $previous = $func; } } diff --git a/src/Network/Probe.php b/src/Network/Probe.php index 5f665814b4..8e44c8a50b 100644 --- a/src/Network/Probe.php +++ b/src/Network/Probe.php @@ -109,6 +109,7 @@ class Probe $redirects = 0; logger("Probing for ".$host, LOGGER_DEBUG); + $xrd = null; $ret = Network::curl($ssl_url, false, $redirects, ['timeout' => $xrd_timeout, 'accept_content' => 'application/xrd+xml']); if ($ret['success']) { @@ -1510,6 +1511,7 @@ class Probe return false; } $feed = $ret['body']; + $dummy1 = $dummy2 = $dummy3 = null; $feed_data = Feed::import($feed, $dummy1, $dummy2, $dummy3, true); if (!$feed_data) { diff --git a/tests/ApiTest.php b/tests/ApiTest.php index c21f651d5f..4c63af7a91 100644 --- a/tests/ApiTest.php +++ b/tests/ApiTest.php @@ -629,7 +629,7 @@ class ApiTest extends DatabaseTest */ public function testApiRssExtra() { - $user_info = ['url' => 'user_url']; + $user_info = ['url' => 'user_url', 'language' => 'en']; $result = api_rss_extra($this->app, [], $user_info); $this->assertEquals($user_info, $result['$user']); $this->assertEquals($user_info['url'], $result['$rss']['alternate']); @@ -1073,6 +1073,7 @@ class ApiTest extends DatabaseTest 'width' => 666, 'height' => 666, 'tmp_name' => $this->getTempImage(), + 'name' => 'spacer.png', 'type' => 'image/png' ] ]; From a329ce5b50fc118b8f5aa97e3c4ad6b8c941664c Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 1 Jul 2018 00:16:32 -0400 Subject: [PATCH 12/65] Fix $called_api expecting at least 2 elements in tests --- include/api.php | 1 + tests/ApiTest.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/api.php b/include/api.php index 6d38be95b7..a9a1800af1 100644 --- a/include/api.php +++ b/include/api.php @@ -575,6 +575,7 @@ function api_get_user(App $a, $contact_id = null) } } + // $called_api is the API path exploded on / and is expected to have at least 2 elements if (is_null($user) && ($a->argc > (count($called_api) - 1)) && (count($called_api) > 0)) { $argid = count($called_api); list($user, $null) = explode(".", $a->argv[$argid]); diff --git a/tests/ApiTest.php b/tests/ApiTest.php index 4c63af7a91..982f5bf11a 100644 --- a/tests/ApiTest.php +++ b/tests/ApiTest.php @@ -818,7 +818,7 @@ class ApiTest extends DatabaseTest public function testApiGetUserWithCalledApi() { global $called_api; - $called_api = ['api_path']; + $called_api = ['api', 'api_path']; $this->assertSelfUser(api_get_user($this->app)); } From 209510e970d3676f6d8986d7b12d6b26702d9939 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 1 Jul 2018 00:17:07 -0400 Subject: [PATCH 13/65] Replace PHP_EOL with \n to conform to code behavior on Windows in tests --- tests/ApiTest.php | 67 +++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/tests/ApiTest.php b/tests/ApiTest.php index 982f5bf11a..0d9e0b538b 100644 --- a/tests/ApiTest.php +++ b/tests/ApiTest.php @@ -481,7 +481,7 @@ class ApiTest extends DatabaseTest $this->app->query_string = 'api_path.rss'; $this->assertEquals( - ''.PHP_EOL. + ''."\n". 'some_data', api_call($this->app) ); @@ -505,7 +505,7 @@ class ApiTest extends DatabaseTest $this->app->query_string = 'api_path.atom'; $this->assertEquals( - ''.PHP_EOL. + ''."\n". 'some_data', api_call($this->app) ); @@ -571,14 +571,14 @@ class ApiTest extends DatabaseTest public function testApiErrorWithXml() { $this->assertEquals( - ''.PHP_EOL. + ''."\n". ''.PHP_EOL. - ' error_message'.PHP_EOL. - ' 200 Friendica\Network\HTTP'.PHP_EOL. - ' '.PHP_EOL. - ''.PHP_EOL, + 'xmlns:georss="http://www.georss.org/georss">'."\n". + ' error_message'."\n". + ' 200 Friendica\Network\HTTP'."\n". + ' '."\n". + ''."\n", api_error('xml', new HTTPException('error_message')) ); } @@ -591,14 +591,14 @@ class ApiTest extends DatabaseTest public function testApiErrorWithRss() { $this->assertEquals( - ''.PHP_EOL. + ''."\n". ''.PHP_EOL. - ' error_message'.PHP_EOL. - ' 200 Friendica\Network\HTTP'.PHP_EOL. - ' '.PHP_EOL. - ''.PHP_EOL, + 'xmlns:georss="http://www.georss.org/georss">'."\n". + ' error_message'."\n". + ' 200 Friendica\Network\HTTP'."\n". + ' '."\n". + ''."\n", api_error('rss', new HTTPException('error_message')) ); } @@ -611,14 +611,14 @@ class ApiTest extends DatabaseTest public function testApiErrorWithAtom() { $this->assertEquals( - ''.PHP_EOL. + ''."\n". ''.PHP_EOL. - ' error_message'.PHP_EOL. - ' 200 Friendica\Network\HTTP'.PHP_EOL. - ' '.PHP_EOL. - ''.PHP_EOL, + 'xmlns:georss="http://www.georss.org/georss">'."\n". + ' error_message'."\n". + ' 200 Friendica\Network\HTTP'."\n". + ' '."\n". + ''."\n", api_error('atom', new HTTPException('error_message')) ); } @@ -853,7 +853,6 @@ class ApiTest extends DatabaseTest $this->assertSelfUser(api_get_user($this->app, 0)); } - /** * Test the api_item_get_user() function. * @return void @@ -957,12 +956,12 @@ class ApiTest extends DatabaseTest public function testApiCreateXml() { $this->assertEquals( - ''.PHP_EOL. + ''."\n". ''.PHP_EOL. - ' some_data'.PHP_EOL. - ''.PHP_EOL, + 'xmlns:georss="http://www.georss.org/georss">'."\n". + ' some_data'."\n". + ''."\n", api_create_xml(['data' => ['some_data']], 'root_element') ); } @@ -974,10 +973,10 @@ class ApiTest extends DatabaseTest public function testApiCreateXmlWithoutNamespaces() { $this->assertEquals( - ''.PHP_EOL. - ''.PHP_EOL. - ' some_data'.PHP_EOL. - ''.PHP_EOL, + ''."\n". + ''."\n". + ' some_data'."\n". + ''."\n", api_create_xml(['data' => ['some_data']], 'ok') ); } @@ -999,12 +998,12 @@ class ApiTest extends DatabaseTest public function testApiFormatDataWithXml() { $this->assertEquals( - ''.PHP_EOL. + ''."\n". ''.PHP_EOL. - ' some_data'.PHP_EOL. - ''.PHP_EOL, + 'xmlns:georss="http://www.georss.org/georss">'."\n". + ' some_data'."\n". + ''."\n", api_format_data('root_element', 'xml', ['data' => ['some_data']]) ); } @@ -1963,7 +1962,7 @@ class ApiTest extends DatabaseTest ['id' => 2, 'screen_name' => 'recipient_name'], ['id' => 3, 'screen_name' => 'sender_name'] ); - $this->assertEquals('item_title'.PHP_EOL.'item_body', $result['text']); + $this->assertEquals('item_title'."\n".'item_body', $result['text']); $this->assertEquals(1, $result['id']); $this->assertEquals(2, $result['recipient_id']); $this->assertEquals(3, $result['sender_id']); From a380bcd1c1d7fe127ee845d7dc5d40523da82461 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 1 Jul 2018 04:03:57 -0400 Subject: [PATCH 14/65] Fix more undefined variable/index notice in tests --- include/api.php | 2 +- include/text.php | 4 ++-- mod/item.php | 22 +++++++++++---------- mod/wall_upload.php | 40 +++++++++++++++++++++++--------------- src/Model/Conversation.php | 2 +- src/Model/Item.php | 2 +- tests/ApiTest.php | 2 ++ 7 files changed, 43 insertions(+), 31 deletions(-) diff --git a/include/api.php b/include/api.php index a9a1800af1..85f489b799 100644 --- a/include/api.php +++ b/include/api.php @@ -1482,7 +1482,7 @@ function api_users_lookup($type) { $users = []; - if (x($_REQUEST['user_id'])) { + if (!empty($_REQUEST['user_id'])) { foreach (explode(',', $_REQUEST['user_id']) as $id) { if (!empty($id)) { $users[] = api_get_user(get_app(), $id); diff --git a/include/text.php b/include/text.php index 04bbb67244..0066e18814 100644 --- a/include/text.php +++ b/include/text.php @@ -1156,7 +1156,7 @@ function put_item_in_cache(&$item, $update = false) $rendered_html = defaults($item, 'rendered-html', ''); if ($rendered_hash == '' - || $item["rendered-html"] == "" + || $rendered_html == "" || $rendered_hash != hash("md5", $item["body"]) || Config::get("system", "ignore_cache") ) { @@ -1176,7 +1176,7 @@ function put_item_in_cache(&$item, $update = false) $update = true; } - if ($update && ($item["id"] > 0)) { + if ($update && !empty($item["id"])) { Item::update(['rendered-html' => $item["rendered-html"], 'rendered-hash' => $item["rendered-hash"]], ['id' => $item["id"]]); } diff --git a/mod/item.php b/mod/item.php index be9fa09c47..95eaa9d78c 100644 --- a/mod/item.php +++ b/mod/item.php @@ -178,6 +178,8 @@ function item_post(App $a) { return; } + $categories = ''; + if ($orig_post) { $str_group_allow = $orig_post['allow_gid']; $str_contact_allow = $orig_post['allow_cid']; @@ -223,13 +225,13 @@ function item_post(App $a) { $str_contact_deny = perms2str($_REQUEST['contact_deny']); } - $title = notags(trim($_REQUEST['title'])); - $location = notags(trim($_REQUEST['location'])); - $coord = notags(trim($_REQUEST['coord'])); - $verb = notags(trim($_REQUEST['verb'])); - $emailcc = notags(trim($_REQUEST['emailcc'])); - $body = escape_tags(trim($_REQUEST['body'])); - $network = notags(trim(defaults($_REQUEST, 'network', NETWORK_DFRN))); + $title = notags(trim(defaults($_REQUEST, 'title' , ''))); + $location = notags(trim(defaults($_REQUEST, 'location', ''))); + $coord = notags(trim(defaults($_REQUEST, 'coord' , ''))); + $verb = notags(trim(defaults($_REQUEST, 'verb' , ''))); + $emailcc = notags(trim(defaults($_REQUEST, 'emailcc' , ''))); + $body = escape_tags(trim(defaults($_REQUEST, 'body' , ''))); + $network = notags(trim(defaults($_REQUEST, 'network' , NETWORK_DFRN))); $guid = get_guid(32); $postopts = defaults($_REQUEST, 'postopts', ''); @@ -279,15 +281,15 @@ function item_post(App $a) { } } - if (strlen($categories)) { + if (!empty($categories)) { // get the "fileas" tags for this post $filedas = file_tag_file_to_list($categories, 'file'); } // save old and new categories, so we can determine what needs to be deleted from pconfig $categories_old = $categories; - $categories = file_tag_list_to_file(trim($_REQUEST['category']), 'category'); + $categories = file_tag_list_to_file(trim(defaults($_REQUEST, 'category', '')), 'category'); $categories_new = $categories; - if (strlen($filedas)) { + if (!empty($filedas)) { // append the fileas stuff to the new categories list $categories .= file_tag_list_to_file($filedas, 'file'); } diff --git a/mod/wall_upload.php b/mod/wall_upload.php index 7067077eb7..8bf2966152 100644 --- a/mod/wall_upload.php +++ b/mod/wall_upload.php @@ -125,28 +125,36 @@ function wall_upload_post(App $a, $desktopmode = true) $filetype = $_FILES['userfile']['type']; } elseif (x($_FILES, 'media')) { - if (is_array($_FILES['media']['tmp_name'])) { - $src = $_FILES['media']['tmp_name'][0]; - } else { - $src = $_FILES['media']['tmp_name']; + if (!empty($_FILES['media']['tmp_name'])) { + if (is_array($_FILES['media']['tmp_name'])) { + $src = $_FILES['media']['tmp_name'][0]; + } else { + $src = $_FILES['media']['tmp_name']; + } } - if (is_array($_FILES['media']['name'])) { - $filename = basename($_FILES['media']['name'][0]); - } else { - $filename = basename($_FILES['media']['name']); + if (!empty($_FILES['media']['name'])) { + if (is_array($_FILES['media']['name'])) { + $filename = basename($_FILES['media']['name'][0]); + } else { + $filename = basename($_FILES['media']['name']); + } } - if (is_array($_FILES['media']['size'])) { - $filesize = intval($_FILES['media']['size'][0]); - } else { - $filesize = intval($_FILES['media']['size']); + if (!empty($_FILES['media']['size'])) { + if (is_array($_FILES['media']['size'])) { + $filesize = intval($_FILES['media']['size'][0]); + } else { + $filesize = intval($_FILES['media']['size']); + } } - if (is_array($_FILES['media']['type'])) { - $filetype = $_FILES['media']['type'][0]; - } else { - $filetype = $_FILES['media']['type']; + if (!empty($_FILES['media']['type'])) { + if (is_array($_FILES['media']['type'])) { + $filetype = $_FILES['media']['type'][0]; + } else { + $filetype = $_FILES['media']['type']; + } } } diff --git a/src/Model/Conversation.php b/src/Model/Conversation.php index 17f151fe03..69bbc3bb6d 100644 --- a/src/Model/Conversation.php +++ b/src/Model/Conversation.php @@ -61,7 +61,7 @@ class Conversation unset($old_conv['source']); } // Update structure data all the time but the source only when its from a better protocol. - if (($old_conv['protocol'] < $conversation['protocol']) && ($old_conv['protocol'] != 0)) { + if (isset($conversation['protocol']) && isset($conversation['source']) && ($old_conv['protocol'] < $conversation['protocol']) && ($old_conv['protocol'] != 0)) { unset($conversation['protocol']); unset($conversation['source']); } diff --git a/src/Model/Item.php b/src/Model/Item.php index 9fbe973eed..5d858fa72b 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -1989,7 +1989,7 @@ class Item extends BaseObject Contact::unmarkForArchival($contact); } - $update = (!$arr['private'] && (($arr["author-link"] === $arr["owner-link"]) || ($arr["parent-uri"] === $arr["uri"]))); + $update = (!$arr['private'] && ((defaults($arr, 'author-link', '') === defaults($arr, 'owner-link', '')) || ($arr["parent-uri"] === $arr["uri"]))); // Is it a forum? Then we don't care about the rules from above if (!$update && ($arr["network"] == NETWORK_DFRN) && ($arr["parent-uri"] === $arr["uri"])) { diff --git a/tests/ApiTest.php b/tests/ApiTest.php index 0d9e0b538b..f1857ad272 100644 --- a/tests/ApiTest.php +++ b/tests/ApiTest.php @@ -1110,6 +1110,7 @@ class ApiTest extends DatabaseTest 'width' => 666, 'height' => 666, 'tmp_name' => $this->getTempImage(), + 'name' => 'spacer.png', 'type' => 'image/png' ] ]; @@ -1217,6 +1218,7 @@ class ApiTest extends DatabaseTest 'width' => 666, 'height' => 666, 'tmp_name' => $this->getTempImage(), + 'name' => 'spacer.png', 'type' => 'image/png' ] ]; From 89e4629c16d7eaf3d78878f7c401f862aa5dd96f Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Mon, 2 Jul 2018 07:47:42 -0400 Subject: [PATCH 15/65] Replace system.proc_windows config by PHP_OS test --- src/App.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App.php b/src/App.php index 22678f53ee..38c4370168 100644 --- a/src/App.php +++ b/src/App.php @@ -878,7 +878,7 @@ class App return; } - if (Config::get('system', 'proc_windows')) { + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { $resource = proc_open('cmd /c start /b ' . $cmdline, [], $foo, $this->get_basepath()); } else { $resource = proc_open($cmdline . ' &', [], $foo, $this->get_basepath()); From 0ee153e1bdebc344746bfea682c2d044b9c5c350 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 1 Jul 2018 04:05:02 -0400 Subject: [PATCH 16/65] Fix Array to String conversion message for IN conditions --- include/dba.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/dba.php b/include/dba.php index 17c62b8144..9d828f8b44 100644 --- a/include/dba.php +++ b/include/dba.php @@ -1015,7 +1015,7 @@ class dba { $commands = []; // Create a key for the loop prevention - $key = $table . ':' . implode(':', array_keys($conditions)) . ':' . implode(':', $conditions); + $key = $table . ':' . json_encode($conditions); // We quit when this key already exists in the callstack. if (isset($callstack[$key])) { @@ -1042,7 +1042,7 @@ class dba { $rel_def = array_values(self::$relation[$table])[0]; // Create a key for preventing double queries - $qkey = $field . '-' . $table . ':' . implode(':', array_keys($conditions)) . ':' . implode(':', $conditions); + $qkey = $field . '-' . $table . ':' . json_encode($conditions); // When the search field is the relation field, we don't need to fetch the rows // This is useful when the leading record is already deleted in the frontend but the rest is done in the backend From 07e06341df52f9cb6e4fda2b9f18e4c058ed169b Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 1 Jul 2018 04:05:52 -0400 Subject: [PATCH 17/65] Simplify config.php_path access in App->proc_run --- src/App.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App.php b/src/App.php index 38c4370168..f4f5545bb3 100644 --- a/src/App.php +++ b/src/App.php @@ -866,7 +866,7 @@ class App return; } - array_unshift($args, ((x($this->config, 'php_path')) && (strlen($this->config['php_path'])) ? $this->config['php_path'] : 'php')); + array_unshift($args, $this->getConfigValue('config', 'php_path', 'php')); for ($x = 0; $x < count($args); $x ++) { $args[$x] = escapeshellarg($args[$x]); From 62eba4867994364de1ddccd2e58f3330004812ad Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 1 Jul 2018 05:17:59 -0400 Subject: [PATCH 18/65] Fix yet more undefined variable/index messages in api_statuses_show --- include/api.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/include/api.php b/include/api.php index 85f489b799..90212a6c3a 100644 --- a/include/api.php +++ b/include/api.php @@ -1806,20 +1806,20 @@ function api_statuses_show($type) } // params - $id = intval($a->argv[3]); + $id = intval(defaults($a->argv, 3, 0)); if ($id == 0) { - $id = intval($_REQUEST["id"]); + $id = intval(defaults($_REQUEST, 'id', 0)); } // Hotot workaround if ($id == 0) { - $id = intval($a->argv[4]); + $id = intval(defaults($a->argv, 4, 0)); } logger('API: api_statuses_show: ' . $id); - $conversation = (x($_REQUEST, 'conversation') ? 1 : 0); + $conversation = !empty($_REQUEST['conversation']); // try to fetch the item for the local user - or the public item, if there is no local one $uri_item = dba::selectFirst('item', ['uri'], ['id' => $id]); @@ -1879,24 +1879,24 @@ function api_conversation_show($type) } // params - $id = intval($a->argv[3]); - $count = (x($_REQUEST, 'count') ? $_REQUEST['count'] : 20); - $page = (x($_REQUEST, 'page') ? $_REQUEST['page'] - 1 : 0); + $id = intval(defaults($a->argv , 3 , 0)); + $since_id = intval(defaults($_REQUEST, 'since_id', 0)); + $max_id = intval(defaults($_REQUEST, 'max_id' , 0)); + $count = intval(defaults($_REQUEST, 'count' , 20)); + $page = intval(defaults($_REQUEST, 'page' , 1)) - 1; if ($page < 0) { $page = 0; } - $since_id = (x($_REQUEST, 'since_id') ? $_REQUEST['since_id'] : 0); - $max_id = (x($_REQUEST, 'max_id') ? $_REQUEST['max_id'] : 0); - $start = $page*$count; + $start = $page * $count; if ($id == 0) { - $id = intval($_REQUEST["id"]); + $id = intval(defaults($_REQUEST, 'id', 0)); } // Hotot workaround if ($id == 0) { - $id = intval($a->argv[4]); + $id = intval(defaults($a->argv, 4, 0)); } logger('API: api_conversation_show: '.$id); From dde61a77a4bb0ff249c8e8025cb2ba4ebe14b88b Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 1 Jul 2018 14:40:56 -0400 Subject: [PATCH 19/65] Fix root element containing only text in api_create_xml() --- include/api.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/api.php b/include/api.php index 90212a6c3a..029f45257f 100644 --- a/include/api.php +++ b/include/api.php @@ -885,7 +885,6 @@ function api_create_xml(array $data, $root_element) { $childname = key($data); $data2 = array_pop($data); - $key = key($data2); $namespaces = ["" => "http://api.twitter.com", "statusnet" => "http://status.net/schema/api/1/", @@ -898,18 +897,19 @@ function api_create_xml(array $data, $root_element) } if (is_array($data2)) { + $key = key($data2); api_walk_recursive($data2, "api_reformat_xml"); - } - if ($key == "0") { - $data4 = []; - $i = 1; + if ($key == "0") { + $data4 = []; + $i = 1; - foreach ($data2 as $item) { - $data4[$i++ . ":" . $childname] = $item; + foreach ($data2 as $item) { + $data4[$i++ . ":" . $childname] = $item; + } + + $data2 = $data4; } - - $data2 = $data4; } $data3 = [$root_element => $data2]; From 757fd357f6a2bfd97ecf0aed38657b00ad7d50a2 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 1 Jul 2018 14:42:38 -0400 Subject: [PATCH 20/65] Fix yet more undefined variable/index notice in api --- include/api.php | 92 +++++++++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 41 deletions(-) diff --git a/include/api.php b/include/api.php index 029f45257f..596428aed5 100644 --- a/include/api.php +++ b/include/api.php @@ -16,6 +16,7 @@ use Friendica\Core\Config; use Friendica\Core\L10n; use Friendica\Core\NotificationsManager; use Friendica\Core\PConfig; +use Friendica\Core\Protocol; use Friendica\Core\System; use Friendica\Core\Worker; use Friendica\Database\DBM; @@ -1959,15 +1960,15 @@ function api_statuses_repeat($type) api_get_user($a); // params - $id = intval($a->argv[3]); + $id = intval(defaults($a->argv, 3, 0)); if ($id == 0) { - $id = intval($_REQUEST["id"]); + $id = intval(defaults($_REQUEST, 'id', 0)); } // Hotot workaround if ($id == 0) { - $id = intval($a->argv[4]); + $id = intval(defaults($a->argv, 4, 0)); } logger('API: api_statuses_repeat: '.$id); @@ -2025,15 +2026,15 @@ function api_statuses_destroy($type) api_get_user($a); // params - $id = intval($a->argv[3]); + $id = intval(defaults($a->argv, 3, 0)); if ($id == 0) { - $id = intval($_REQUEST["id"]); + $id = intval(defaults($_REQUEST, 'id', 0)); } // Hotot workaround if ($id == 0) { - $id = intval($a->argv[4]); + $id = intval(defaults($a->argv, 4, 0)); } logger('API: api_statuses_destroy: '.$id); @@ -2219,10 +2220,9 @@ function api_favorites_create_destroy($type) } $action = str_replace("." . $type, "", $a->argv[$action_argv_id]); if ($a->argc == $action_argv_id + 2) { - $itemid = intval($a->argv[$action_argv_id + 1]); + $itemid = intval(defaults($a->argv, $action_argv_id + 1, 0)); } else { - /// @TODO use x() to check if _REQUEST contains 'id' - $itemid = intval($_REQUEST['id']); + $itemid = intval(defaults($_REQUEST, 'id', 0)); } $item = Item::selectFirstForUser(api_user(), [], ['id' => $itemid, 'uid' => api_user()]); @@ -2345,25 +2345,33 @@ function api_format_messages($item, $recipient, $sender) { // standard meta information $ret = [ - 'id' => $item['id'], - 'sender_id' => $sender['id'] , - 'text' => "", - 'recipient_id' => $recipient['id'], - 'created_at' => api_date($item['created']), - 'sender_screen_name' => $sender['screen_name'], - 'recipient_screen_name' => $recipient['screen_name'], - 'sender' => $sender, - 'recipient' => $recipient, - 'title' => "", - 'friendica_seen' => $item['seen'], - 'friendica_parent_uri' => $item['parent-uri'], + 'id' => $item['id'], + 'sender_id' => $sender['id'] , + 'text' => "", + 'recipient_id' => $recipient['id'], + 'created_at' => api_date(defaults($item, 'created', DateTimeFormat::utcNow())), + 'sender_screen_name' => $sender['screen_name'], + 'recipient_screen_name' => $recipient['screen_name'], + 'sender' => $sender, + 'recipient' => $recipient, + 'title' => "", + 'friendica_seen' => defaults($item, 'seen', 0), + 'friendica_parent_uri' => defaults($item, 'parent-uri', ''), ]; // "uid" and "self" are only needed for some internal stuff, so remove it from here - unset($ret["sender"]["uid"]); - unset($ret["sender"]["self"]); - unset($ret["recipient"]["uid"]); - unset($ret["recipient"]["self"]); + if (isset($ret['sender']['uid'])) { + unset($ret['sender']['uid']); + } + if (isset($ret['sender']['self'])) { + unset($ret['sender']['self']); + } + if (isset($ret['recipient']['uid'])) { + unset($ret['recipient']['uid']); + } + if (isset($ret['recipient']['self'])) { + unset($ret['recipient']['self']); + } //don't send title to regular StatusNET requests to avoid confusing these apps if (x($_GET, 'getText')) { @@ -2410,8 +2418,8 @@ function api_convert_item($item) $statustext = trim($statustitle."\n\n".$statusbody); } - if (($item["network"] == NETWORK_FEED) && (strlen($statustext)> 1000)) { - $statustext = substr($statustext, 0, 1000)."... \n".$item["plink"]; + if ((defaults($item, 'network', Protocol::PHANTOM) == Protocol::FEED) && (strlen($statustext)> 1000)) { + $statustext = substr($statustext, 0, 1000) . "... \n" . defaults($item, 'plink', ''); } $statushtml = BBCode::convert(api_clean_attachments($body), false); @@ -2445,7 +2453,7 @@ function api_convert_item($item) } // feeds without body should contain the link - if (($item['network'] == NETWORK_FEED) && (strlen($item['body']) == 0)) { + if ((defaults($item, 'network', Protocol::PHANTOM) == Protocol::FEED) && (strlen($item['body']) == 0)) { $statushtml .= BBCode::convert($item['plink']); } @@ -2487,7 +2495,7 @@ function api_get_attachments(&$body) } } - if (strstr($_SERVER['HTTP_USER_AGENT'], "AndStatus")) { + if (strstr(defaults($_SERVER, 'HTTP_USER_AGENT', ''), "AndStatus")) { foreach ($images[0] as $orig) { $body = str_replace($orig, "", $body); } @@ -3462,20 +3470,20 @@ api_register_func('api/followers/ids', 'api_followers_ids', true); */ function api_direct_messages_new($type) { - $a = get_app(); if (api_user() === false) { throw new ForbiddenException(); } - if (!x($_POST, "text") || (!x($_POST, "screen_name") && !x($_POST, "user_id"))) { + if (empty($_POST["text"]) || empty($_POST["screen_name"]) && empty($_POST["user_id"])) { return; } $sender = api_get_user($a); - if ($_POST['screen_name']) { + $recipient = null; + if (!empty($_POST['screen_name'])) { $r = q( "SELECT `id`, `nurl`, `network` FROM `contact` WHERE `uid`=%d AND `nick`='%s'", intval(api_user()), @@ -3627,17 +3635,17 @@ function api_direct_messages_box($type, $box, $verbose) throw new ForbiddenException(); } // params - $count = (x($_GET, 'count') ? $_GET['count'] : 20); - $page = (x($_REQUEST, 'page') ? $_REQUEST['page'] -1 : 0); + $count = defaults($_GET, 'count', 20); + $page = defaults($_REQUEST, 'page', 1) - 1; if ($page < 0) { $page = 0; } - $since_id = (x($_REQUEST, 'since_id') ? $_REQUEST['since_id'] : 0); - $max_id = (x($_REQUEST, 'max_id') ? $_REQUEST['max_id'] : 0); + $since_id = defaults($_REQUEST, 'since_id', 0); + $max_id = defaults($_REQUEST, 'max_id', 0); - $user_id = (x($_REQUEST, 'user_id') ? $_REQUEST['user_id'] : ""); - $screen_name = (x($_REQUEST, 'screen_name') ? $_REQUEST['screen_name'] : ""); + $user_id = defaults($_REQUEST, 'user_id', ''); + $screen_name = defaults($_REQUEST, 'screen_name', ''); // caller user info unset($_REQUEST["user_id"]); @@ -3661,7 +3669,7 @@ function api_direct_messages_box($type, $box, $verbose) if ($box=="sentbox") { $sql_extra = "`mail`.`from-url`='" . dbesc($profile_url) . "'"; } elseif ($box == "conversation") { - $sql_extra = "`mail`.`parent-uri`='" . dbesc($_GET["uri"]) . "'"; + $sql_extra = "`mail`.`parent-uri`='" . dbesc(defaults($_GET, 'uri', '')) . "'"; } elseif ($box == "all") { $sql_extra = "true"; } elseif ($box == "inbox") { @@ -5582,8 +5590,10 @@ function api_friendica_notification($type) if ($type == "xml") { $xmlnotes = []; - foreach ($notes as $note) { - $xmlnotes[] = ["@attributes" => $note]; + if (!empty($notes)) { + foreach ($notes as $note) { + $xmlnotes[] = ["@attributes" => $note]; + } } $notes = $xmlnotes; From cb7176ee7051cc90e3fb6d5c9816e875112a90d1 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 1 Jul 2018 14:42:58 -0400 Subject: [PATCH 21/65] Fix Config use in api_statusnet_config() --- include/api.php | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/include/api.php b/include/api.php index 596428aed5..bd16206a58 100644 --- a/include/api.php +++ b/include/api.php @@ -3337,18 +3337,15 @@ function api_statusnet_config($type) { $a = get_app(); - $name = $a->config['sitename']; - $server = $a->get_hostname(); - $logo = System::baseUrl() . '/images/friendica-64.png'; - $email = $a->config['admin_email']; - $closed = (($a->config['register_policy'] == REGISTER_CLOSED) ? 'true' : 'false'); - $private = ((Config::get('system', 'block_public')) ? 'true' : 'false'); - $textlimit = (string) (($a->config['max_import_size']) ? $a->config['max_import_size'] : 200000); - if ($a->config['api_import_size']) { - $textlimit = (string) $a->config['api_import_size']; - } - $ssl = ((Config::get('system', 'have_ssl')) ? 'true' : 'false'); - $sslserver = (($ssl === 'true') ? str_replace('http:', 'https:', System::baseUrl()) : ''); + $name = Config::get('config', 'sitename'); + $server = $a->get_hostname(); + $logo = System::baseUrl() . '/images/friendica-64.png'; + $email = Config::get('config', 'admin_email'); + $closed = Config::get('config', 'register_policy') == REGISTER_CLOSED ? 'true' : 'false'; + $private = Config::get('system', 'block_public') ? 'true' : 'false'; + $textlimit = (string) Config::get('config', 'api_import_size', Config::get('config', 'max_import_size', 200000)); + $ssl = Config::get('system', 'have_ssl') ? 'true' : 'false'; + $sslserver = Config::get('system', 'have_ssl') ? str_replace('http:', 'https:', System::baseUrl()) : ''; $config = [ 'site' => ['name' => $name,'server' => $server, 'theme' => 'default', 'path' => '', From 43688c04b16c093444a29f15193d9911fb84df2f Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 1 Jul 2018 14:43:22 -0400 Subject: [PATCH 22/65] Add NotFoundException for recipients in api_direct_messages_new() --- include/api.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/include/api.php b/include/api.php index bd16206a58..cae93a372b 100644 --- a/include/api.php +++ b/include/api.php @@ -3487,14 +3487,20 @@ function api_direct_messages_new($type) dbesc($_POST['screen_name']) ); - // Selecting the id by priority, friendica first - api_best_nickname($r); + if (DBM::is_result($r)) { + // Selecting the id by priority, friendica first + api_best_nickname($r); - $recipient = api_get_user($a, $r[0]['nurl']); + $recipient = api_get_user($a, $r[0]['nurl']); + } } else { $recipient = api_get_user($a, $_POST['user_id']); } + if (empty($recipient)) { + throw new NotFoundException('Recipient not found'); + } + $replyto = ''; $sub = ''; if (x($_REQUEST, 'replyto')) { From 18eb13a5980ca560ba51e38b8a585e1f2c2c804e Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 1 Jul 2018 14:46:24 -0400 Subject: [PATCH 23/65] Fix API test cases - Add meaningful app->argv/c - Add support for subfolder install - Add meaningful image URL from placeholder.com - Fix incomplete test testApiHelpTestWithXml() - Use $this->frienduser for direct messages tests - Fix dataset to have an actual contact relationship --- tests/ApiTest.php | 95 ++++++++++++++++++++++++------------------ tests/datasets/api.yml | 2 +- 2 files changed, 56 insertions(+), 41 deletions(-) diff --git a/tests/ApiTest.php b/tests/ApiTest.php index f1857ad272..10b7849eb6 100644 --- a/tests/ApiTest.php +++ b/tests/ApiTest.php @@ -29,18 +29,28 @@ class ApiTest extends DatabaseTest global $a; parent::setUp(); + // Reusable App object + $this->app = new App(__DIR__.'/../'); + $a = $this->app; + // User data that the test database is populated with $this->selfUser = [ 'id' => 42, 'name' => 'Self contact', 'nick' => 'selfcontact', - 'nurl' => 'http://localhost/profile/selfcontact' + 'nurl' => \Friendica\Core\System::baseUrl() . '/profile/selfcontact' + ]; + $this->friendUser = [ + 'id' => 44, + 'name' => 'Friend contact', + 'nick' => 'friendcontact', + 'nurl' => \Friendica\Core\System::baseUrl() . '/profile/friendcontact' ]; $this->otherUser = [ 'id' => 43, 'name' => 'othercontact', 'nick' => 'othercontact', - 'nurl' => 'http://localhost/profile/othercontact' + 'nurl' => \Friendica\Core\System::baseUrl() . '/profile/othercontact' ]; // User ID that we know is not in the database @@ -53,10 +63,6 @@ class ApiTest extends DatabaseTest 'uid' => $this->selfUser['id'] ]; - // Reusable App object - $this->app = new App(__DIR__.'/../'); - $a = $this->app; - // Default config Config::set('config', 'hostname', 'localhost'); Config::set('system', 'throttle_limit_day', 100); @@ -1835,6 +1841,8 @@ class ApiTest extends DatabaseTest */ public function testApiFavoritesCreateDestroy() { + $this->app->argv = ['api', '1.1', 'favorites', 'create']; + $this->app->argc = count($this->app->argv); api_favorites_create_destroy('json'); } @@ -1845,9 +1853,8 @@ class ApiTest extends DatabaseTest */ public function testApiFavoritesCreateDestroyWithInvalidId() { - // This triggers a very specific condition ($action_argv_id + 2) - $this->app->argv[1] = '1.1'; - $this->app->argc = 5; + $this->app->argv = ['api', '1.1', 'favorites', 'create', '12.json']; + $this->app->argc = count($this->app->argv); api_favorites_create_destroy('json'); } @@ -1858,8 +1865,8 @@ class ApiTest extends DatabaseTest */ public function testApiFavoritesCreateDestroyWithInvalidAction() { - $this->app->argv[1] = '1.1'; - $this->app->argc = 10; + $this->app->argv = ['api', '1.1', 'favorites', 'change.json']; + $this->app->argc = count($this->app->argv); $_REQUEST['id'] = 1; api_favorites_create_destroy('json'); } @@ -1870,9 +1877,8 @@ class ApiTest extends DatabaseTest */ public function testApiFavoritesCreateDestroyWithCreateAction() { - $this->app->argv[1] = '1.1'; - $this->app->argv[3] = 'create'; - $this->app->argc = 10; + $this->app->argv = ['api', '1.1', 'favorites', 'create.json']; + $this->app->argc = count($this->app->argv); $_REQUEST['id'] = 3; $result = api_favorites_create_destroy('json'); $this->assertStatus($result['status']); @@ -1884,9 +1890,8 @@ class ApiTest extends DatabaseTest */ public function testApiFavoritesCreateDestroyWithCreateActionAndRss() { - $this->app->argv[1] = '1.1'; - $this->app->argv[3] = 'create'; - $this->app->argc = 10; + $this->app->argv = ['api', '1.1', 'favorites', 'create.rss']; + $this->app->argc = count($this->app->argv); $_REQUEST['id'] = 3; $result = api_favorites_create_destroy('rss'); $this->assertXml($result, 'status'); @@ -1898,9 +1903,8 @@ class ApiTest extends DatabaseTest */ public function testApiFavoritesCreateDestroyWithDestroyAction() { - $this->app->argv[1] = '1.1'; - $this->app->argv[3] = 'destroy'; - $this->app->argc = 10; + $this->app->argv = ['api', '1.1', 'favorites', 'destroy.json']; + $this->app->argc = count($this->app->argv); $_REQUEST['id'] = 3; $result = api_favorites_create_destroy('json'); $this->assertStatus($result['status']); @@ -1913,6 +1917,8 @@ class ApiTest extends DatabaseTest */ public function testApiFavoritesCreateDestroyWithoutAuthenticatedUser() { + $this->app->argv = ['api', '1.1', 'favorites', 'create.json']; + $this->app->argc = count($this->app->argv); $_SESSION['authenticated'] = false; api_favorites_create_destroy('json'); } @@ -2016,8 +2022,8 @@ class ApiTest extends DatabaseTest ['id' => 2, 'screen_name' => 'recipient_name'], ['id' => 3, 'screen_name' => 'sender_name'] ); - $this->assertNull($result['sender']); - $this->assertNull($result['recipient']); + $this->assertTrue(!isset($result['sender'])); + $this->assertTrue(!isset($result['recipient'])); } /** @@ -2053,7 +2059,8 @@ class ApiTest extends DatabaseTest 'repellat officia illum quos impedit quam iste esse unde qui '. 'suscipit aut facilis ut inventore omnis exercitationem quo magnam '. 'consequatur maxime aut illum soluta quaerat natus unde aspernatur '. - 'et sed beatae nihil ullam temporibus corporis ratione blanditiis' + 'et sed beatae nihil ullam temporibus corporis ratione blanditiis', + 'plink' => 'item_plink' ] ); $this->assertStringStartsWith('item_title', $result['text']); @@ -2110,7 +2117,7 @@ class ApiTest extends DatabaseTest */ public function testApiGetAttachmentsWithImage() { - $body = '[img]img_url[/img]'; + $body = '[img]http://via.placeholder.com/1x1.png[/img]'; $this->assertInternalType('array', api_get_attachments($body)); } @@ -2121,7 +2128,7 @@ class ApiTest extends DatabaseTest public function testApiGetAttachmentsWithImageAndAndStatus() { $_SERVER['HTTP_USER_AGENT'] = 'AndStatus'; - $body = '[img]img_url[/img]'; + $body = '[img]http://via.placeholder.com/1x1.png[/img]'; $this->assertInternalType('array', api_get_attachments($body)); } @@ -2157,7 +2164,7 @@ class ApiTest extends DatabaseTest public function testApiFormatItemsEmbededImages() { $this->assertEquals( - 'text http://localhost/display/item_guid', + 'text ' . \Friendica\Core\System::baseUrl() . '/display/item_guid', api_format_items_embeded_images(['guid' => 'item_guid'], 'text data:image/foo') ); } @@ -2198,7 +2205,7 @@ class ApiTest extends DatabaseTest */ public function testApiFormatItemsActivities() { - $item = []; + $item = ['uid' => 0, 'uri' => '']; $result = api_format_items_activities($item); $this->assertArrayHasKey('like', $result); $this->assertArrayHasKey('dislike', $result); @@ -2213,7 +2220,7 @@ class ApiTest extends DatabaseTest */ public function testApiFormatItemsActivitiesWithXml() { - $item = []; + $item = ['uid' => 0, 'uri' => '']; $result = api_format_items_activities($item, 'xml'); $this->assertArrayHasKey('friendica:like', $result); $this->assertArrayHasKey('friendica:dislike', $result); @@ -2327,10 +2334,14 @@ class ApiTest extends DatabaseTest [ 'item_network' => 'item_network', 'source' => 'web', - 'coord' => '5 7' + 'coord' => '5 7', + 'body' => '', + 'verb' => '', + 'author-id' => 42, + 'plink' => '', ] ]; - $result = api_format_items($items, [], true); + $result = api_format_items($items, ['id' => 0], true); foreach ($result as $status) { $this->assertStatus($status); } @@ -2344,10 +2355,14 @@ class ApiTest extends DatabaseTest { $items = [ [ - 'coord' => '5 7' + 'coord' => '5 7', + 'body' => '', + 'verb' => '', + 'author-id' => 42, + 'plink' => '', ] ]; - $result = api_format_items($items, [], true, 'xml'); + $result = api_format_items($items, ['id' => 0], true, 'xml'); foreach ($result as $status) { $this->assertStatus($status); } @@ -2391,7 +2406,6 @@ class ApiTest extends DatabaseTest */ public function testApiHelpTestWithXml() { - $this->markTestIncomplete('Triggers this error: "key() expects parameter 1 to be array, string given"'); $result = api_help_test('xml'); $this->assertXml($result, 'ok'); } @@ -2617,7 +2631,7 @@ class ApiTest extends DatabaseTest $result = api_statusnet_config('json'); $this->assertEquals('localhost', $result['config']['site']['server']); $this->assertEquals('default', $result['config']['site']['theme']); - $this->assertEquals('http://localhost/images/friendica-64.png', $result['config']['site']['logo']); + $this->assertEquals(\Friendica\Core\System::baseUrl() . '/images/friendica-64.png', $result['config']['site']['logo']); $this->assertTrue($result['config']['site']['fancy']); $this->assertEquals('en', $result['config']['site']['language']); $this->assertEquals('UTC', $result['config']['site']['timezone']); @@ -2727,7 +2741,7 @@ class ApiTest extends DatabaseTest public function testApiDirectMessagesNewWithScreenName() { $_POST['text'] = 'message_text'; - $_POST['screen_name'] = $this->otherUser['nick']; + $_POST['screen_name'] = $this->friendUser['nick']; $result = api_direct_messages_new('json'); $this->assertEquals(1, $result['direct_message']['id']); $this->assertContains('message_text', $result['direct_message']['text']); @@ -2742,7 +2756,7 @@ class ApiTest extends DatabaseTest public function testApiDirectMessagesNewWithTitle() { $_POST['text'] = 'message_text'; - $_POST['screen_name'] = $this->otherUser['nick']; + $_POST['screen_name'] = $this->friendUser['nick']; $_REQUEST['title'] = 'message_title'; $result = api_direct_messages_new('json'); $this->assertEquals(1, $result['direct_message']['id']); @@ -2759,7 +2773,7 @@ class ApiTest extends DatabaseTest public function testApiDirectMessagesNewWithRss() { $_POST['text'] = 'message_text'; - $_POST['screen_name'] = $this->otherUser['nick']; + $_POST['screen_name'] = $this->friendUser['nick']; $result = api_direct_messages_new('rss'); $this->assertXml($result, 'direct-messages'); } @@ -3564,7 +3578,8 @@ class ApiTest extends DatabaseTest */ public function testApiFriendicaNotificationWithArgumentCount() { - $this->app->argc = 3; + $this->app->argv = ['api', 'friendica', 'notification']; + $this->app->argc = count($this->app->argv); $result = api_friendica_notification('json'); $this->assertEquals(['note' => false], $result); } @@ -3575,8 +3590,8 @@ class ApiTest extends DatabaseTest */ public function testApiFriendicaNotificationWithXmlResult() { - $this->markTestIncomplete('Fails with "Invalid argument supplied for foreach()".'); - $this->app->argc = 3; + $this->app->argv = ['api', 'friendica', 'notification']; + $this->app->argc = count($this->app->argv); $result = api_friendica_notification('xml'); $this->assertXml($result, 'notes'); } diff --git a/tests/datasets/api.yml b/tests/datasets/api.yml index 9ba5ec387e..f3bd08c277 100644 --- a/tests/datasets/api.yml +++ b/tests/datasets/api.yml @@ -34,7 +34,7 @@ contact: network: dfrn - id: 43 - uid: 0 + uid: 42 # Having the same name and nick allows us to test # the fallback to api_get_nick() in api_get_user() name: othercontact From 633a71ec970ab23a47838705fe951df1e9a8cea9 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 1 Jul 2018 14:46:45 -0400 Subject: [PATCH 24/65] Fix notice in Item::deleteById --- src/Model/Item.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Model/Item.php b/src/Model/Item.php index 5d858fa72b..052d402127 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -801,7 +801,9 @@ class Item extends BaseObject // If item has attachments, drop them foreach (explode(", ", $item['attach']) as $attach) { preg_match("|attach/(\d+)|", $attach, $matches); - dba::delete('attach', ['id' => $matches[1], 'uid' => $item['uid']]); + if (is_array($matches) && count($matches) > 1) { + dba::delete('attach', ['id' => $matches[1], 'uid' => $item['uid']]); + } } // Delete tags that had been attached to other items From f91e7c9f1760ca98a5d1ad8643e72191ef99898b Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 1 Jul 2018 15:07:50 -0400 Subject: [PATCH 25/65] Revert using System::baseurl() for mock user nurls --- tests/ApiTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ApiTest.php b/tests/ApiTest.php index 10b7849eb6..160fb1b966 100644 --- a/tests/ApiTest.php +++ b/tests/ApiTest.php @@ -38,19 +38,19 @@ class ApiTest extends DatabaseTest 'id' => 42, 'name' => 'Self contact', 'nick' => 'selfcontact', - 'nurl' => \Friendica\Core\System::baseUrl() . '/profile/selfcontact' + 'nurl' => 'http://localhost/profile/selfcontact' ]; $this->friendUser = [ 'id' => 44, 'name' => 'Friend contact', 'nick' => 'friendcontact', - 'nurl' => \Friendica\Core\System::baseUrl() . '/profile/friendcontact' + 'nurl' => 'http://localhost/profile/friendcontact' ]; $this->otherUser = [ 'id' => 43, 'name' => 'othercontact', 'nick' => 'othercontact', - 'nurl' => \Friendica\Core\System::baseUrl() . '/profile/othercontact' + 'nurl' => 'http://localhost/profile/othercontact' ]; // User ID that we know is not in the database From 39b61da05d9d1a96d6eadc13022169b216720525 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 1 Jul 2018 15:08:14 -0400 Subject: [PATCH 26/65] Fix last undefined variable/index messages in tests --- tests/ApiTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ApiTest.php b/tests/ApiTest.php index 160fb1b966..34ca7ddf0c 100644 --- a/tests/ApiTest.php +++ b/tests/ApiTest.php @@ -3373,7 +3373,7 @@ class ApiTest extends DatabaseTest */ public function testApiShareAsRetweet() { - $item = []; + $item = ['body' => '']; $result = api_share_as_retweet($item); $this->assertFalse($result); } @@ -3413,7 +3413,7 @@ class ApiTest extends DatabaseTest */ public function testApiInReplyTo() { - $result = api_in_reply_to([]); + $result = api_in_reply_to(['id' => 0, 'parent' => 0, 'uri' => '', 'thr-parent' => '']); $this->assertArrayHasKey('status_id', $result); $this->assertArrayHasKey('user_id', $result); $this->assertArrayHasKey('status_id_str', $result); From 58e1470ddb52ba1203db67227dcdb7c725727a6e Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Mon, 2 Jul 2018 22:19:21 -0400 Subject: [PATCH 27/65] Fix Undefined index: HTTP_USER_AGENT in App --- src/App.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App.php b/src/App.php index f4f5545bb3..92ff057138 100644 --- a/src/App.php +++ b/src/App.php @@ -293,7 +293,7 @@ class App $this->is_tablet = $mobile_detect->isTablet(); // Friendica-Client - $this->is_friendica_app = ($_SERVER['HTTP_USER_AGENT'] == 'Apache-HttpClient/UNAVAILABLE (java 1.4)'); + $this->is_friendica_app = isset($_SERVER['HTTP_USER_AGENT']) && $_SERVER['HTTP_USER_AGENT'] == 'Apache-HttpClient/UNAVAILABLE (java 1.4)'; // Register template engines $this->register_template_engine('Friendica\Render\FriendicaSmartyEngine'); From e7d6b48bb334df22349934c374827352b2801094 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Mon, 2 Jul 2018 22:28:27 -0400 Subject: [PATCH 28/65] Fix Undefined index: Collation in DBStructure --- src/Database/DBStructure.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Database/DBStructure.php b/src/Database/DBStructure.php index db6997ec62..dc570f3135 100644 --- a/src/Database/DBStructure.php +++ b/src/Database/DBStructure.php @@ -537,26 +537,26 @@ class DBStructure private static function FieldCommand($parameters, $create = true) { $fieldstruct = $parameters["type"]; - if (!is_null($parameters["Collation"])) { + if (!empty($parameters["Collation"])) { $fieldstruct .= " COLLATE ".$parameters["Collation"]; } - if ($parameters["not null"]) { + if (!empty($parameters["not null"])) { $fieldstruct .= " NOT NULL"; } - if (isset($parameters["default"])) { + if (!empty($parameters["default"])) { if (strpos(strtolower($parameters["type"]),"int")!==false) { $fieldstruct .= " DEFAULT ".$parameters["default"]; } else { $fieldstruct .= " DEFAULT '".$parameters["default"]."'"; } } - if ($parameters["extra"] != "") { + if (!empty($parameters["extra"])) { $fieldstruct .= " ".$parameters["extra"]; } - if (!is_null($parameters["comment"])) { + if (!empty($parameters["comment"])) { $fieldstruct .= " COMMENT '".dbesc($parameters["comment"])."'"; } From 79ff49d71617baa34a53954114962992d3f80e8d Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Mon, 2 Jul 2018 22:42:15 -0400 Subject: [PATCH 29/65] Replace more is_null with empty in DBStructure --- src/Database/DBStructure.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Database/DBStructure.php b/src/Database/DBStructure.php index dc570f3135..d4cb9cf58b 100644 --- a/src/Database/DBStructure.php +++ b/src/Database/DBStructure.php @@ -413,7 +413,7 @@ class DBStructure $field_definition = $database[$name]["fields"][$fieldname]; // Define the default collation if not given - if (!isset($parameters['Collation']) && !is_null($field_definition['Collation'])) { + if (!isset($parameters['Collation']) && !empty($field_definition['Collation'])) { $parameters['Collation'] = 'utf8mb4_general_ci'; } else { $parameters['Collation'] = null; @@ -580,7 +580,7 @@ class DBStructure } } - if (!is_null($structure["indexes"])) { + if (!empty($structure["indexes"])) { foreach ($structure["indexes"] AS $indexname => $fieldnames) { $sql_index = self::createIndex($indexname, $fieldnames, ""); if (!is_null($sql_index)) { @@ -589,11 +589,11 @@ class DBStructure } } - if (!is_null($structure["engine"])) { + if (!empty($structure["engine"])) { $engine = " ENGINE=" . $structure["engine"]; } - if (!is_null($structure["comment"])) { + if (!empty($structure["comment"])) { $comment = " COMMENT='" . dbesc($structure["comment"]) . "'"; } From 9cce1f70f98347cdd94265b93c74ef661d3fa3bf Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Mon, 2 Jul 2018 23:10:33 -0400 Subject: [PATCH 30/65] Add .htconfig.php in test setUp --- tests/DatabaseTest.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/DatabaseTest.php b/tests/DatabaseTest.php index 12150932c9..408e4b0cd3 100644 --- a/tests/DatabaseTest.php +++ b/tests/DatabaseTest.php @@ -20,6 +20,30 @@ abstract class DatabaseTest extends TestCase use TestCaseTrait; + /** + * Creates .htconfig.php for bin/worker.php execution + */ + protected function setUp() + { + parent::setUp(); + + $base_config_file_name = 'htconfig.php'; + $config_file_name = '.htconfig.php'; + + $base_config_file_path = stream_resolve_include_path($base_config_file_name); + $config_file_path = dirname($base_config_file_path) . DIRECTORY_SEPARATOR . $config_file_name; + + $config_string = file_get_contents($base_config_file_path); + + $config_string = str_replace('die(', '// die('); + $config_string = str_replace('your.mysqlhost.com', 'localhost'); + $config_string = str_replace('mysqlusername' , getenv('USER')); + $config_string = str_replace('mysqlpassword' , getenv('PASS')); + $config_string = str_replace('mysqldatabasename' , getenv('DB')); + + file_put_contents($config_file_path, $config_string); + } + /** * Get database connection. * From 4752ea13749373de36b32e0d4a7fe11e742f363c Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Mon, 2 Jul 2018 23:10:33 -0400 Subject: [PATCH 31/65] Add .htconfig.php in test setUp --- tests/DatabaseTest.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/DatabaseTest.php b/tests/DatabaseTest.php index 12150932c9..6edd45e575 100644 --- a/tests/DatabaseTest.php +++ b/tests/DatabaseTest.php @@ -20,6 +20,30 @@ abstract class DatabaseTest extends TestCase use TestCaseTrait; + /** + * Creates .htconfig.php for bin/worker.php execution + */ + protected function setUp() + { + parent::setUp(); + + $base_config_file_name = 'htconfig.php'; + $config_file_name = '.htconfig.php'; + + $base_config_file_path = stream_resolve_include_path($base_config_file_name); + $config_file_path = dirname($base_config_file_path) . DIRECTORY_SEPARATOR . $config_file_name; + + $config_string = file_get_contents($base_config_file_path); + + $config_string = str_replace('die(', '// die(', $config_string); + $config_string = str_replace('your.mysqlhost.com', 'localhost', $config_string); + $config_string = str_replace('mysqlusername' , getenv('USER'), $config_string); + $config_string = str_replace('mysqlpassword' , getenv('PASS'), $config_string); + $config_string = str_replace('mysqldatabasename' , getenv('DB'), $config_string); + + file_put_contents($config_file_path, $config_string); + } + /** * Get database connection. * From f9747708d859d0c8fa4141eec5612ae93f7ac57e Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Tue, 3 Jul 2018 08:44:14 -0400 Subject: [PATCH 32/65] Add verbose to PHPUnit config --- phpunit.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/phpunit.xml b/phpunit.xml index b2d978aee6..b6f6247f67 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,5 +1,7 @@ - + tests/ From d31e3b16fff8b9887ed2c4761ed2a8ad5bc0559e Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Tue, 3 Jul 2018 21:22:10 -0400 Subject: [PATCH 33/65] Fix boolean values in test data --- tests/datasets/api.yml | 96 +++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/tests/datasets/api.yml b/tests/datasets/api.yml index f3bd08c277..eacb30a507 100644 --- a/tests/datasets/api.yml +++ b/tests/datasets/api.yml @@ -14,7 +14,7 @@ user: uid: 42 username: Test user nickname: selfcontact - verified: true + verified: 1 password: $2y$10$DLRNTRmJgKe1cSrFJ5Jb0edCqvXlA9sh/RHdSnfxjbR.04yZRm4Qm theme: frio @@ -24,12 +24,12 @@ contact: uid: 42 name: Self contact nick: selfcontact - self: true + self: 1 nurl: http://localhost/profile/selfcontact url: http://localhost/profile/selfcontact about: User used in tests - pending: false - blocked: false + pending: 0 + blocked: 0 rel: 1 network: dfrn - @@ -39,11 +39,11 @@ contact: # the fallback to api_get_nick() in api_get_user() name: othercontact nick: othercontact - self: false + self: 0 nurl: http://localhost/profile/othercontact url: http://localhost/profile/othercontact - pending: false - blocked: false + pending: 0 + blocked: 0 rel: 0 network: dfrn - @@ -51,150 +51,150 @@ contact: uid: 0 name: Friend contact nick: friendcontact - self: false + self: 0 nurl: http://localhost/profile/friendcontact url: http://localhost/profile/friendcontact - pending: false - blocked: false + pending: 0 + blocked: 0 rel: 2 network: dfrn item: - id: 1 - visible: true + visible: 1 contact-id: 42 author-id: 42 owner-id: 45 uid: 42 verb: http://activitystrea.ms/schema/1.0/post - unseen: true + unseen: 1 body: Parent status parent: 1 author-link: http://localhost/profile/selfcontact - wall: true - starred: true - origin: true + wall: 1 + starred: 1 + origin: 1 allow_cid: '' allow_gid: '' deny_cid: '' deny_gid: '' - id: 2 - visible: true + visible: 1 contact-id: 42 author-id: 42 owner-id: 45 uid: 42 verb: http://activitystrea.ms/schema/1.0/post - unseen: false + unseen: 0 body: Reply parent: 1 author-link: http://localhost/profile/selfcontact - wall: true - starred: false - origin: true + wall: 1 + starred: 0 + origin: 1 - id: 3 - visible: true + visible: 1 contact-id: 43 author-id: 43 owner-id: 42 uid: 42 verb: http://activitystrea.ms/schema/1.0/post - unseen: false + unseen: 0 body: Other user status parent: 3 author-link: http://localhost/profile/othercontact - wall: true - starred: false - origin: true + wall: 1 + starred: 0 + origin: 1 - id: 4 - visible: true + visible: 1 contact-id: 44 author-id: 44 owner-id: 42 uid: 42 verb: http://activitystrea.ms/schema/1.0/post - unseen: false + unseen: 0 body: Friend user reply parent: 1 author-link: http://localhost/profile/othercontact - wall: true - starred: false - origin: true + wall: 1 + starred: 0 + origin: 1 - id: 5 - visible: true + visible: 1 contact-id: 42 author-id: 42 owner-id: 42 uid: 42 verb: http://activitystrea.ms/schema/1.0/post - unseen: false + unseen: 0 body: '[share]Shared status[/share]' parent: 1 author-link: http://localhost/profile/othercontact - wall: true - starred: false - origin: true + wall: 1 + starred: 0 + origin: 1 allow_cid: '' allow_gid: '' deny_cid: '' deny_gid: '' - id: 6 - visible: true + visible: 1 contact-id: 44 author-id: 44 owner-id: 42 uid: 42 verb: http://activitystrea.ms/schema/1.0/post - unseen: false + unseen: 0 body: Friend user status parent: 6 author-link: http://localhost/profile/othercontact - wall: true - starred: false - origin: true + wall: 1 + starred: 0 + origin: 1 thread: - iid: 1 - visible: true + visible: 1 contact-id: 42 author-id: 42 owner-id: 42 uid: 42 - wall: true + wall: 1 - iid: 3 - visible: true + visible: 1 contact-id: 43 author-id: 43 owner-id: 43 uid: 0 - wall: true + wall: 1 - iid: 6 - visible: true + visible: 1 contact-id: 44 author-id: 44 owner-id: 44 uid: 0 - wall: true + wall: 1 group: - id: 1 uid: 42 - visible: true + visible: 1 name: Visible list - id: 2 uid: 42 - visible: false + visible: 0 name: Private list search: From 125f7beb63f978f6c610d160b6115ca7e06a92a9 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Tue, 3 Jul 2018 21:22:50 -0400 Subject: [PATCH 34/65] Add creation/deletion of separate .htconfig.php used for tests --- tests/DatabaseTest.php | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/tests/DatabaseTest.php b/tests/DatabaseTest.php index b53d59161a..fd1c90bc61 100644 --- a/tests/DatabaseTest.php +++ b/tests/DatabaseTest.php @@ -21,24 +21,50 @@ abstract class DatabaseTest extends TestCase use TestCaseTrait; /** - * Creates .htconfig.php for bin/worker.php execution + * Renames an eventually existing .htconfig.php to .htconfig.php.tmp + * Creates a new .htconfig.php for bin/worker.php execution */ - protected function setUp() + public static function setUpBeforeClass() { - parent::setUp(); + parent::setUpBeforeClass(); $base_config_file_name = 'htconfig.php'; $config_file_name = '.htconfig.php'; $base_config_file_path = stream_resolve_include_path($base_config_file_name); $config_file_path = dirname($base_config_file_path) . DIRECTORY_SEPARATOR . $config_file_name; + $config_file_path_tmp = $config_file_path . '.tmp'; - if (!file_exists($config_file_path)) { - $config_string = file_get_contents($base_config_file_path); + if (file_exists($config_file_path)) { + rename($config_file_path, $config_file_path_tmp); + } - $config_string = str_replace('die(', '// die(', $config_string); + $config_string = file_get_contents($base_config_file_path); - file_put_contents($config_file_path, $config_string); + $config_string = str_replace('die(', '// die(', $config_string); + + file_put_contents($config_file_path, $config_string); + } + + /** + * Delete the created .htconfig.php + * Renames an eventually existing .htconfig.php.tmp to .htconfig.php + */ + public static function tearDownAfterClass() + { + $base_config_file_name = 'htconfig.php'; + $config_file_name = '.htconfig.php'; + + $base_config_file_path = stream_resolve_include_path($base_config_file_name); + $config_file_path = dirname($base_config_file_path) . DIRECTORY_SEPARATOR . $config_file_name; + $config_file_path_tmp = $config_file_path . '.tmp'; + + if (file_exists($config_file_path)) { + unlink($config_file_path); + } + + if (file_exists($config_file_path_tmp)) { + rename($config_file_path_tmp, $config_file_path); } } From 40d911c284e5b2e399dfa530053ca1c8b5b57ff5 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Tue, 3 Jul 2018 21:24:16 -0400 Subject: [PATCH 35/65] Use correct App mode to disable logging - Restore normal mode after DBStructure update - Improve error message in case of missing DB connection --- tests/DatabaseTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/DatabaseTest.php b/tests/DatabaseTest.php index fd1c90bc61..73165f10a4 100644 --- a/tests/DatabaseTest.php +++ b/tests/DatabaseTest.php @@ -87,12 +87,14 @@ abstract class DatabaseTest extends TestCase if (dba::$connected) { $app = get_app(); // We need to do this in order to disable logging - $app->module = 'install'; + $app->mode = \Friendica\App::MODE_INSTALL; // Create database structure DBStructure::update(false, true, true); + + $app->mode = \Friendica\App::MODE_NORMAL; } else { - $this->markTestSkipped('Could not connect to the database.'); + $this->markTestSkipped('Could not connect to the database. Please check the MYSQL_* environment variables.'); } } From 7e279cc301ffab128097eee0ef13a8bdcb43c5b4 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Tue, 3 Jul 2018 21:24:42 -0400 Subject: [PATCH 36/65] Add DB structure import from file during Travis execution --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index b722fe77f1..78c29817db 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,3 +16,4 @@ install: - composer install before_script: - mysql -e 'CREATE DATABASE IF NOT EXISTS test;' + - mysql -utravis test < database.sql From b256f5cf2c642df203ceb6703e7d9e3e5b0ffdce Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Tue, 3 Jul 2018 22:46:45 -0400 Subject: [PATCH 37/65] Fix missing env variable replacement --- tests/DatabaseTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/DatabaseTest.php b/tests/DatabaseTest.php index 73165f10a4..e79e9237be 100644 --- a/tests/DatabaseTest.php +++ b/tests/DatabaseTest.php @@ -98,7 +98,7 @@ abstract class DatabaseTest extends TestCase } } - return $this->createDefaultDBConnection(dba::get_db(), getenv('DB')); + return $this->createDefaultDBConnection(dba::get_db(), getenv('MYSQL_DATABASE')); } /** From 8ad41d4f1594fc08d5723ed305da73286175687c Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Tue, 3 Jul 2018 23:14:03 -0400 Subject: [PATCH 38/65] Add debug to database test --- tests/DatabaseTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/DatabaseTest.php b/tests/DatabaseTest.php index e79e9237be..df681acbf4 100644 --- a/tests/DatabaseTest.php +++ b/tests/DatabaseTest.php @@ -93,6 +93,8 @@ abstract class DatabaseTest extends TestCase DBStructure::update(false, true, true); $app->mode = \Friendica\App::MODE_NORMAL; + + var_dump(dba::inArray(\dba::select('contact'))); } else { $this->markTestSkipped('Could not connect to the database. Please check the MYSQL_* environment variables.'); } From 3e9ff5ef6e77481b76488ffa360c0f5cbfa86285 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Tue, 3 Jul 2018 23:20:33 -0400 Subject: [PATCH 39/65] Move debug --- tests/ApiTest.php | 2 ++ tests/DatabaseTest.php | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ApiTest.php b/tests/ApiTest.php index 34ca7ddf0c..9575a8af0c 100644 --- a/tests/ApiTest.php +++ b/tests/ApiTest.php @@ -3393,6 +3393,8 @@ class ApiTest extends DatabaseTest */ public function testApiGetNick() { + var_dump(dba::inArray(\dba::select('contact'))); + $result = api_get_nick($this->otherUser['nurl']); $this->assertEquals('othercontact', $result); } diff --git a/tests/DatabaseTest.php b/tests/DatabaseTest.php index df681acbf4..e79e9237be 100644 --- a/tests/DatabaseTest.php +++ b/tests/DatabaseTest.php @@ -93,8 +93,6 @@ abstract class DatabaseTest extends TestCase DBStructure::update(false, true, true); $app->mode = \Friendica\App::MODE_NORMAL; - - var_dump(dba::inArray(\dba::select('contact'))); } else { $this->markTestSkipped('Could not connect to the database. Please check the MYSQL_* environment variables.'); } From 675333f246587080c118917df8ccd46ffed184cf Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Tue, 3 Jul 2018 23:27:12 -0400 Subject: [PATCH 40/65] Bleh --- tests/ApiTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/ApiTest.php b/tests/ApiTest.php index 9575a8af0c..81f77531de 100644 --- a/tests/ApiTest.php +++ b/tests/ApiTest.php @@ -12,6 +12,8 @@ use Friendica\Network\BadRequestException; use Friendica\Network\HTTPException; use Friendica\Render\FriendicaSmarty; +require_once 'include/dba.php'; + /** * Tests for the API functions. * @@ -3393,7 +3395,7 @@ class ApiTest extends DatabaseTest */ public function testApiGetNick() { - var_dump(dba::inArray(\dba::select('contact'))); + var_dump(\dba::inArray(\dba::select('contact'))); $result = api_get_nick($this->otherUser['nurl']); $this->assertEquals('othercontact', $result); From b2b984433c3313fb40de774dc02f8450ccc1cded Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Tue, 3 Jul 2018 23:37:52 -0400 Subject: [PATCH 41/65] Fix dataset ids for otheruser/frienduser Remove debug --- tests/ApiTest.php | 6 +----- tests/datasets/api.yml | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/tests/ApiTest.php b/tests/ApiTest.php index 81f77531de..c7f3f8cd65 100644 --- a/tests/ApiTest.php +++ b/tests/ApiTest.php @@ -12,8 +12,6 @@ use Friendica\Network\BadRequestException; use Friendica\Network\HTTPException; use Friendica\Render\FriendicaSmarty; -require_once 'include/dba.php'; - /** * Tests for the API functions. * @@ -2731,7 +2729,7 @@ class ApiTest extends DatabaseTest public function testApiDirectMessagesNewWithUserId() { $_POST['text'] = 'message_text'; - $_POST['user_id'] = $this->otherUser['id']; + $_POST['user_id'] = $this->friendUser['id']; $result = api_direct_messages_new('json'); $this->assertEquals(['direct_message' => ['error' => -1]], $result); } @@ -3395,8 +3393,6 @@ class ApiTest extends DatabaseTest */ public function testApiGetNick() { - var_dump(\dba::inArray(\dba::select('contact'))); - $result = api_get_nick($this->otherUser['nurl']); $this->assertEquals('othercontact', $result); } diff --git a/tests/datasets/api.yml b/tests/datasets/api.yml index eacb30a507..25c9dade60 100644 --- a/tests/datasets/api.yml +++ b/tests/datasets/api.yml @@ -34,7 +34,7 @@ contact: network: dfrn - id: 43 - uid: 42 + uid: 0 # Having the same name and nick allows us to test # the fallback to api_get_nick() in api_get_user() name: othercontact @@ -48,7 +48,7 @@ contact: network: dfrn - id: 44 - uid: 0 + uid: 42 name: Friend contact nick: friendcontact self: 0 From 3a89ab199be96bf451257c619986c80f11b8742c Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 4 Jul 2018 00:09:17 -0400 Subject: [PATCH 42/65] Fix tests error/failures - Fix undenifed index: author-network notice - Fix assertion mismatch in testApiDirectMessagesNewWithUserId --- tests/ApiTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/ApiTest.php b/tests/ApiTest.php index c7f3f8cd65..1a94b0d46a 100644 --- a/tests/ApiTest.php +++ b/tests/ApiTest.php @@ -2338,6 +2338,7 @@ class ApiTest extends DatabaseTest 'body' => '', 'verb' => '', 'author-id' => 42, + 'author-network' => \Friendica\Core\Protocol::DFRN, 'plink' => '', ] ]; @@ -2359,6 +2360,7 @@ class ApiTest extends DatabaseTest 'body' => '', 'verb' => '', 'author-id' => 42, + 'author-network' => \Friendica\Core\Protocol::DFRN, 'plink' => '', ] ]; @@ -2729,7 +2731,7 @@ class ApiTest extends DatabaseTest public function testApiDirectMessagesNewWithUserId() { $_POST['text'] = 'message_text'; - $_POST['user_id'] = $this->friendUser['id']; + $_POST['user_id'] = $this->otherUser['id']; $result = api_direct_messages_new('json'); $this->assertEquals(['direct_message' => ['error' => -1]], $result); } From cdab9b4cd276d33ce6ff1654063d2b40b13ed23e Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 4 Jul 2018 00:54:53 -0400 Subject: [PATCH 43/65] Add missing author-link property to testFormatItems* --- tests/ApiTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/ApiTest.php b/tests/ApiTest.php index 1a94b0d46a..d54d0cc9a3 100644 --- a/tests/ApiTest.php +++ b/tests/ApiTest.php @@ -2337,8 +2337,9 @@ class ApiTest extends DatabaseTest 'coord' => '5 7', 'body' => '', 'verb' => '', - 'author-id' => 42, + 'author-id' => 43, 'author-network' => \Friendica\Core\Protocol::DFRN, + 'author-link' => 'http://localhost/profile/othercontact', 'plink' => '', ] ]; @@ -2359,8 +2360,9 @@ class ApiTest extends DatabaseTest 'coord' => '5 7', 'body' => '', 'verb' => '', - 'author-id' => 42, + 'author-id' => 43, 'author-network' => \Friendica\Core\Protocol::DFRN, + 'author-link' => 'http://localhost/profile/othercontact', 'plink' => '', ] ]; From e44111e935b6356dc6f8928d713173ff96bf7c61 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 4 Jul 2018 17:33:09 -0400 Subject: [PATCH 44/65] Revert renaming lang to language in api - Normalize some quotes - Put "Empty user-agent" log message in a else statement --- include/api.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/include/api.php b/include/api.php index cae93a372b..af6f54fe60 100644 --- a/include/api.php +++ b/include/api.php @@ -97,10 +97,10 @@ function api_source() } logger("Unrecognized user-agent ".$_SERVER['HTTP_USER_AGENT'], LOGGER_DEBUG); + } else { + logger("Empty user-agent", LOGGER_DEBUG); } - logger("Empty user-agent", LOGGER_DEBUG); - return "api"; } @@ -480,7 +480,7 @@ function api_rss_extra(App $a, $arr, $user_info) 'base' => System::baseUrl(), 'updated' => api_date(null), 'atom_updated' => DateTimeFormat::utcNow(DateTimeFormat::ATOM), - 'language' => $user_info['language'], + 'language' => $user_info['lang'], 'logo' => System::baseUrl() . "/images/friendica-32.png", ]; @@ -665,7 +665,7 @@ function api_get_user(App $a, $contact_id = null) 'geo_enabled' => false, 'verified' => false, 'statuses_count' => 0, - 'language' => '', + 'lang' => '', 'contributors_enabled' => false, 'is_translator' => false, 'is_translation_enabled' => false, @@ -746,7 +746,7 @@ function api_get_user(App $a, $contact_id = null) 'geo_enabled' => false, 'verified' => true, 'statuses_count' => intval($countitems), - 'language' => '', + 'lang' => '', 'contributors_enabled' => false, 'is_translator' => false, 'is_translation_enabled' => false, @@ -1305,19 +1305,19 @@ function api_status_show($type) 'in_reply_to_screen_name' => $in_reply_to['screen_name'], 'user' => $user_info, $geo => null, - 'coordinates' => "", - 'place' => "", - 'contributors' => "", + 'coordinates' => '', + 'place' => '', + 'contributors' => '', 'is_quote_status' => false, 'retweet_count' => 0, 'favorite_count' => 0, 'favorited' => $lastwall['starred'] ? true : false, 'retweeted' => false, 'possibly_sensitive' => false, - 'language' => "", + 'lang' => '', 'statusnet_html' => $converted["html"], 'statusnet_conversation_id' => $lastwall['parent'], - 'external_url' => System::baseUrl() . "/display/" . $lastwall['guid'], + 'external_url' => System::baseUrl() . '/display/' . $lastwall['guid'], ]; if (count($converted["attachments"]) > 0) { From aac94d1d7445f2287f89a3559f4b3988e39edbdb Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Wed, 4 Jul 2018 23:37:22 +0200 Subject: [PATCH 45/65] Adding multihost - locking Adding Unit-Tests for it --- boot.php | 2 +- src/Core/Cache/ArrayCache.php | 83 ++++++++++++++++ src/Core/Cache/DatabaseCacheDriver.php | 4 +- src/Core/Cache/ICacheDriver.php | 15 ++- src/Core/Cache/IMemoryCacheDriver.php | 45 +++++++++ src/Core/Cache/MemcacheCacheDriver.php | 48 ++++++++-- src/Core/Cache/MemcachedCacheDriver.php | 38 ++++++-- src/Core/Cache/RedisCacheDriver.php | 92 ++++++++++++++++-- src/Core/Cache/TraitCompareDelete.php | 45 +++++++++ src/Core/Cache/TraitCompareSet.php | 48 ++++++++++ src/Core/Lock.php | 17 +++- src/Core/Lock/AbstractLockDriver.php | 7 +- src/Core/Lock/CacheLockDriver.php | 68 +++++++------ src/Core/Lock/DatabaseLockDriver.php | 53 +++++----- src/Core/Lock/ILockDriver.php | 8 ++ src/Core/Lock/SemaphoreLockDriver.php | 31 ++++-- src/Database/DBStructure.php | 7 +- tests/datasets/api.yml | 96 +++++++++---------- tests/src/Core/Lock/CacheLockDriverTest.php | 27 ++++++ .../src/Core/Lock/DatabaseLockDriverTest.php | 67 +++++++++++++ tests/src/Core/Lock/LockTest.php | 80 ++++++++++++++++ .../src/Core/Lock/SemaphoreLockDriverTest.php | 14 +++ 22 files changed, 741 insertions(+), 154 deletions(-) create mode 100644 src/Core/Cache/ArrayCache.php create mode 100644 src/Core/Cache/IMemoryCacheDriver.php create mode 100644 src/Core/Cache/TraitCompareDelete.php create mode 100644 src/Core/Cache/TraitCompareSet.php create mode 100644 tests/src/Core/Lock/CacheLockDriverTest.php create mode 100644 tests/src/Core/Lock/DatabaseLockDriverTest.php create mode 100644 tests/src/Core/Lock/LockTest.php create mode 100644 tests/src/Core/Lock/SemaphoreLockDriverTest.php diff --git a/boot.php b/boot.php index 864e7804c9..786a846f32 100644 --- a/boot.php +++ b/boot.php @@ -41,7 +41,7 @@ define('FRIENDICA_PLATFORM', 'Friendica'); define('FRIENDICA_CODENAME', 'The Tazmans Flax-lily'); define('FRIENDICA_VERSION', '2018.08-dev'); define('DFRN_PROTOCOL_VERSION', '2.23'); -define('DB_UPDATE_VERSION', 1272); +define('DB_UPDATE_VERSION', 1273); define('NEW_UPDATE_ROUTINE_VERSION', 1170); /** diff --git a/src/Core/Cache/ArrayCache.php b/src/Core/Cache/ArrayCache.php new file mode 100644 index 0000000000..d4fe8bc7f7 --- /dev/null +++ b/src/Core/Cache/ArrayCache.php @@ -0,0 +1,83 @@ +cachedData[$key])) { + return $this->cachedData[$key]; + } + return null; + } + + /** + * (@inheritdoc) + */ + public function set($key, $value, $ttl = Cache::FIVE_MINUTES) + { + $this->cachedData[$key] = $value; + return true; + } + + /** + * (@inheritdoc) + */ + public function delete($key) + { + unset($this->cachedData[$key]); + return true; + } + + /** + * (@inheritdoc) + */ + public function clear() + { + $this->cachedData = []; + return true; + } + + /** + * (@inheritdoc) + */ + public function add($key, $value, $ttl = Cache::FIVE_MINUTES) + { + if (isset($this->cachedData[$key])) { + return false; + } else { + return $this->set($key, $value, $ttl); + } + } + + /** + * (@inheritdoc) + */ + public function compareSet($key, $oldValue, $newValue, $ttl = Cache::FIVE_MINUTES) + { + if ($this->get($key) === $oldValue) { + return $this->set($key, $newValue); + } else { + return false; + } + } +} \ No newline at end of file diff --git a/src/Core/Cache/DatabaseCacheDriver.php b/src/Core/Cache/DatabaseCacheDriver.php index 7248e0b349..0838a66c7a 100644 --- a/src/Core/Cache/DatabaseCacheDriver.php +++ b/src/Core/Cache/DatabaseCacheDriver.php @@ -33,11 +33,11 @@ class DatabaseCacheDriver implements ICacheDriver return null; } - public function set($key, $value, $duration = Cache::MONTH) + public function set($key, $value, $ttl = Cache::FIVE_MINUTES) { $fields = [ 'v' => serialize($value), - 'expires' => DateTimeFormat::utc('now + ' . $duration . ' seconds'), + 'expires' => DateTimeFormat::utc('now + ' . $ttl . ' seconds'), 'updated' => DateTimeFormat::utcNow() ]; diff --git a/src/Core/Cache/ICacheDriver.php b/src/Core/Cache/ICacheDriver.php index be896edf7f..ff329f34eb 100644 --- a/src/Core/Cache/ICacheDriver.php +++ b/src/Core/Cache/ICacheDriver.php @@ -12,7 +12,7 @@ use Friendica\Core\Cache; interface ICacheDriver { /** - * Fetches cached data according to the key + * @brief Fetches cached data according to the key * * @param string $key The key to the cached data * @@ -21,28 +21,27 @@ interface ICacheDriver public function get($key); /** - * Stores data in the cache identified by the key. The input $value can have multiple formats. + * @brief Stores data in the cache identified by the key. The input $value can have multiple formats. * * @param string $key The cache key * @param mixed $value The value to store - * @param integer $duration The cache lifespan, must be one of the Cache constants + * @param integer $ttl The cache lifespan, must be one of the Cache constants * * @return bool */ - public function set($key, $value, $duration = Cache::MONTH); - + public function set($key, $value, $ttl = Cache::FIVE_MINUTES); /** - * Delete a key from the cache + * @brief Delete a key from the cache * - * @param string $key + * @param string $key The cache key * * @return bool */ public function delete($key); /** - * Remove outdated data from the cache + * @brief Remove outdated data from the cache * * @return bool */ diff --git a/src/Core/Cache/IMemoryCacheDriver.php b/src/Core/Cache/IMemoryCacheDriver.php new file mode 100644 index 0000000000..7843ca7b5f --- /dev/null +++ b/src/Core/Cache/IMemoryCacheDriver.php @@ -0,0 +1,45 @@ + */ -class MemcacheCacheDriver extends BaseObject implements ICacheDriver +class MemcacheCacheDriver extends BaseObject implements IMemoryCacheDriver { + use TraitCompareSet; + use TraitCompareDelete; + /** - * @var Memcache + * @var \Memcache */ private $memcache; @@ -30,6 +33,9 @@ class MemcacheCacheDriver extends BaseObject implements ICacheDriver } } + /** + * (@inheritdoc) + */ public function get($key) { $return = null; @@ -54,17 +60,31 @@ class MemcacheCacheDriver extends BaseObject implements ICacheDriver return $return; } - public function set($key, $value, $duration = Cache::MONTH) + /** + * (@inheritdoc) + */ + public function set($key, $value, $ttl = Cache::FIVE_MINUTES) { // We store with the hostname as key to avoid problems with other applications - return $this->memcache->set( - self::getApp()->get_hostname() . ":" . $key, - serialize($value), - MEMCACHE_COMPRESSED, - time() + $duration - ); + if ($ttl > 0) { + return $this->memcache->set( + self::getApp()->get_hostname() . ":" . $key, + serialize($value), + MEMCACHE_COMPRESSED, + time() + $ttl + ); + } else { + return $this->memcache->set( + self::getApp()->get_hostname() . ":" . $key, + serialize($value), + MEMCACHE_COMPRESSED + ); + } } + /** + * (@inheritdoc) + */ public function delete($key) { return $this->memcache->delete($key); @@ -72,6 +92,14 @@ class MemcacheCacheDriver extends BaseObject implements ICacheDriver public function clear() { - return true; + return $this->memcache->flush(); + } + + /** + * (@inheritdoc) + */ + public function add($key, $value, $ttl = Cache::FIVE_MINUTES) + { + return $this->memcache->add(self::getApp()->get_hostname() . ":" . $key, $value, $ttl); } } diff --git a/src/Core/Cache/MemcachedCacheDriver.php b/src/Core/Cache/MemcachedCacheDriver.php index 78a4a6bdfe..9c860711f8 100644 --- a/src/Core/Cache/MemcachedCacheDriver.php +++ b/src/Core/Cache/MemcachedCacheDriver.php @@ -10,8 +10,11 @@ use Friendica\Core\Cache; * * @author Hypolite Petovan */ -class MemcachedCacheDriver extends BaseObject implements ICacheDriver +class MemcachedCacheDriver extends BaseObject implements IMemoryCacheDriver { + use TraitCompareSet; + use TraitCompareDelete; + /** * @var Memcached */ @@ -46,14 +49,22 @@ class MemcachedCacheDriver extends BaseObject implements ICacheDriver return $return; } - public function set($key, $value, $duration = Cache::MONTH) + public function set($key, $value, $ttl = Cache::FIVE_MINUTES) { // We store with the hostname as key to avoid problems with other applications - return $this->memcached->set( - self::getApp()->get_hostname() . ':' . $key, - $value, - time() + $duration - ); + if ($ttl > 0) { + return $this->memcached->set( + self::getApp()->get_hostname() . ':' . $key, + $value, + time() + $ttl + ); + } else { + return $this->memcached->set( + self::getApp()->get_hostname() . ':' . $key, + $value + ); + } + } public function delete($key) @@ -67,4 +78,17 @@ class MemcachedCacheDriver extends BaseObject implements ICacheDriver { return true; } + + /** + * @brief Sets a value if it's not already stored + * + * @param string $key The cache key + * @param mixed $value The old value we know from the cache + * @param int $ttl The cache lifespan, must be one of the Cache constants + * @return bool + */ + public function add($key, $value, $ttl = Cache::FIVE_MINUTES) + { + return $this->memcached->add(self::getApp()->get_hostname() . ":" . $key, $value, $ttl); + } } diff --git a/src/Core/Cache/RedisCacheDriver.php b/src/Core/Cache/RedisCacheDriver.php index fa98842da0..d23fa2697b 100644 --- a/src/Core/Cache/RedisCacheDriver.php +++ b/src/Core/Cache/RedisCacheDriver.php @@ -11,7 +11,7 @@ use Friendica\Core\Cache; * @author Hypolite Petovan * @author Roland Haeder */ -class RedisCacheDriver extends BaseObject implements ICacheDriver +class RedisCacheDriver extends BaseObject implements IMemoryCacheDriver { /** * @var Redis @@ -55,14 +55,21 @@ class RedisCacheDriver extends BaseObject implements ICacheDriver return $return; } - public function set($key, $value, $duration = Cache::MONTH) + public function set($key, $value, $ttl = Cache::FIVE_MINUTES) { // We store with the hostname as key to avoid problems with other applications - return $this->redis->set( - self::getApp()->get_hostname() . ":" . $key, - serialize($value), - time() + $duration - ); + if ($ttl > 0) { + return $this->redis->setex( + self::getApp()->get_hostname() . ":" . $key, + time() + $ttl, + serialize($value) + ); + } else { + return $this->redis->set( + self::getApp()->get_hostname() . ":" . $key, + serialize($value) + ); + } } public function delete($key) @@ -74,4 +81,75 @@ class RedisCacheDriver extends BaseObject implements ICacheDriver { return true; } + + + /** + * @brief Sets a value if it's not already stored + * + * @param string $key The cache key + * @param mixed $value The old value we know from the cache + * @param int $ttl The cache lifespan, must be one of the Cache constants + * @return bool + */ + public function add($key, $value, $ttl = Cache::FIVE_MINUTES) + { + if (!is_int($value)) { + $value = serialize($value); + } + + return $this->redis->setnx(self::getApp()->get_hostname() . ":" . $key, $value); + } + + /** + * @brief Compares if the old value is set and sets the new value + * + * @param string $key The cache key + * @param mixed $oldValue The old value we know + * @param mixed $newValue The new value we want to set + * @param int $ttl The cache lifespan, must be one of the Cache constants + * @return bool + */ + public function compareSet($key, $oldValue, $newValue, $ttl = Cache::FIVE_MINUTES) + { + if (!is_int($newValue)) { + $newValue = serialize($newValue); + } + + $this->redis->watch(self::getApp()->get_hostname() . ":" . $key); + // If the old value isn't what we expected, somebody else changed the key meanwhile + if ($this->get($key) === $oldValue) { + if ($ttl > 0) { + $result = $this->redis->multi() + ->setex(self::getApp()->get_hostname() . ":" . $ttl, $key, $newValue) + ->exec(); + } else { + $result = $this->redis->multi() + ->set(self::getApp()->get_hostname() . ":" . $key, $newValue) + ->exec(); + } + return $result !== false; + } + $this->redis->unwatch(); + return false; + } + /** + * @brief Compares if the old value is set and removes it + * + * @param string $key The cache key + * @param mixed $value The old value we know and want to delete + * @return bool + */ + public function compareDelete($key, $value) + { + $this->redis->watch(self::getApp()->get_hostname() . ":" . $key); + // If the old value isn't what we expected, somebody else changed the key meanwhile + if ($this->get($key) === $value) { + $result = $this->redis->multi() + ->del(self::getApp()->get_hostname() . ":" . $key) + ->exec(); + return $result !== false; + } + $this->redis->unwatch(); + return false; + } } diff --git a/src/Core/Cache/TraitCompareDelete.php b/src/Core/Cache/TraitCompareDelete.php new file mode 100644 index 0000000000..898e39aecc --- /dev/null +++ b/src/Core/Cache/TraitCompareDelete.php @@ -0,0 +1,45 @@ +add($key . "_lock", true)) { + if ($this->get($key) === $value) { + $this->delete($key); + $this->delete($key . "_lock"); + return true; + } else { + $this->delete($key . "_lock"); + return false; + } + } else { + return false; + } + } +} \ No newline at end of file diff --git a/src/Core/Cache/TraitCompareSet.php b/src/Core/Cache/TraitCompareSet.php new file mode 100644 index 0000000000..55193b7567 --- /dev/null +++ b/src/Core/Cache/TraitCompareSet.php @@ -0,0 +1,48 @@ +add($key . "_lock", true)) { + if ($this->get($key) === $oldValue) { + $this->set($key, $newValue, $ttl); + $this->delete($key . "_lock"); + return true; + } else { + $this->delete($key . "_lock"); + return false; + } + } else { + return false; + } + } +} \ No newline at end of file diff --git a/src/Core/Lock.php b/src/Core/Lock.php index 7db0ea0db6..7235c64a98 100644 --- a/src/Core/Lock.php +++ b/src/Core/Lock.php @@ -10,6 +10,7 @@ namespace Friendica\Core; */ use Friendica\Core\Cache\CacheDriverFactory; +use Friendica\Core\Cache\IMemoryCacheDriver; /** * @brief This class contain Functions for preventing parallel execution of functions @@ -29,17 +30,23 @@ class Lock switch ($lock_driver) { case 'memcache': $cache_driver = CacheDriverFactory::create('memcache'); - self::$driver = new Lock\CacheLockDriver($cache_driver); + if ($cache_driver instanceof IMemoryCacheDriver) { + self::$driver = new Lock\CacheLockDriver($cache_driver); + } break; case 'memcached': $cache_driver = CacheDriverFactory::create('memcached'); - self::$driver = new Lock\CacheLockDriver($cache_driver); + if ($cache_driver instanceof IMemoryCacheDriver) { + self::$driver = new Lock\CacheLockDriver($cache_driver); + } break; case 'redis': $cache_driver = CacheDriverFactory::create('redis'); - self::$driver = new Lock\CacheLockDriver($cache_driver); + if ($cache_driver instanceof IMemoryCacheDriver) { + self::$driver = new Lock\CacheLockDriver($cache_driver); + } break; case 'database': @@ -85,7 +92,9 @@ class Lock if ($cache_driver != 'database') { try { $lock_driver = CacheDriverFactory::create($cache_driver); - self::$driver = new Lock\CacheLockDriver($lock_driver); + if ($lock_driver instanceof IMemoryCacheDriver) { + self::$driver = new Lock\CacheLockDriver($lock_driver); + } return; } catch (\Exception $exception) { logger('Using Cache driver for locking failed: ' . $exception->getMessage()); diff --git a/src/Core/Lock/AbstractLockDriver.php b/src/Core/Lock/AbstractLockDriver.php index bcce26129c..09549c50bf 100644 --- a/src/Core/Lock/AbstractLockDriver.php +++ b/src/Core/Lock/AbstractLockDriver.php @@ -1,6 +1,7 @@ acquireLock[$key]); + return isset($this->acquireLock[$key]) && $this->acquiredLocks[$key] === true; } /** @@ -50,7 +51,7 @@ abstract class AbstractLockDriver implements ILockDriver * @return void */ public function releaseAll() { - foreach ($this->acquiredLocks as $acquiredLock) { + foreach ($this->acquiredLocks as $acquiredLock => $hasLock) { $this->releaseLock($acquiredLock); } } diff --git a/src/Core/Lock/CacheLockDriver.php b/src/Core/Lock/CacheLockDriver.php index 1bb768bd0f..13d912c1e2 100644 --- a/src/Core/Lock/CacheLockDriver.php +++ b/src/Core/Lock/CacheLockDriver.php @@ -2,7 +2,7 @@ namespace Friendica\Core\Lock; -use Friendica\Core\Cache\ICacheDriver; +use Friendica\Core\Cache\IMemoryCacheDriver; class CacheLockDriver extends AbstractLockDriver { @@ -14,9 +14,9 @@ class CacheLockDriver extends AbstractLockDriver /** * CacheLockDriver constructor. * - * @param ICacheDriver $cache The CacheDriver for this type of lock + * @param IMemoryCacheDriver $cache The CacheDriver for this type of lock */ - public function __construct(ICacheDriver $cache) + public function __construct(IMemoryCacheDriver $cache) { $this->cache = $cache; } @@ -35,32 +35,31 @@ class CacheLockDriver extends AbstractLockDriver $got_lock = false; $start = time(); - $cachekey = get_app()->get_hostname() . ";lock:" . $key; + $cachekey = self::getCacheKey($key); do { $lock = $this->cache->get($cachekey); - - if (!is_bool($lock)) { - $pid = (int)$lock; - - // When the process id isn't used anymore, we can safely claim the lock for us. - // Or we do want to lock something that was already locked by us. - if (!posix_kill($pid, 0) || ($pid == getmypid())) { - $lock = false; - } - } - if (is_bool($lock)) { - $this->cache->set($cachekey, getmypid(), 300); + // When we do want to lock something that was already locked by us. + if ((int)$lock == getmypid()) { $got_lock = true; } + // When we do want to lock something new + if (is_null($lock)) { + // At first initialize it with "0" + $this->cache->add($cachekey, 0); + // Now the value has to be "0" because otherwise the key was used by another process meanwhile + if ($this->cache->compareSet($cachekey, 0, getmypid(), 300)) { + $got_lock = true; + $this->markAcquire($key); + } + } + if (!$got_lock && ($timeout > 0)) { usleep(rand(10000, 200000)); } } while (!$got_lock && ((time() - $start) < $timeout)); - $this->markAcquire($key); - return $got_lock; } @@ -68,22 +67,33 @@ class CacheLockDriver extends AbstractLockDriver * @brief Removes a lock if it was set by us * * @param string $key Name of the lock - * - * @return mixed */ public function releaseLock($key) { - $cachekey = get_app()->get_hostname() . ";lock:" . $key; - $lock = $this->cache->get($cachekey); - - if (!is_bool($lock)) { - if ((int)$lock == getmypid()) { - $this->cache->delete($cachekey); - } - } + $cachekey = self::getCacheKey($key); + $this->cache->compareDelete($cachekey, getmypid()); $this->markRelease($key); + } - return; + /** + * @brief Checks, if a key is currently locked to a process + * + * @param string $key The name of the lock + * @return bool + */ + public function isLocked($key) + { + $cachekey = self::getCacheKey($key); + $lock = $this->cache->get($cachekey); + return isset($lock) && ($lock !== false); + } + + /** + * @param string $key The original key + * @return string The cache key used for the cache + */ + private static function getCacheKey($key) { + return self::getApp()->get_hostname() . ";lock:" . $key; } } diff --git a/src/Core/Lock/DatabaseLockDriver.php b/src/Core/Lock/DatabaseLockDriver.php index 9b415753fc..6f4b942a4d 100644 --- a/src/Core/Lock/DatabaseLockDriver.php +++ b/src/Core/Lock/DatabaseLockDriver.php @@ -4,6 +4,7 @@ namespace Friendica\Core\Lock; use dba; use Friendica\Database\DBM; +use Friendica\Util\DateTimeFormat; /** * Locking driver that stores the locks in the database @@ -11,12 +12,7 @@ use Friendica\Database\DBM; class DatabaseLockDriver extends AbstractLockDriver { /** - * @brief Sets a lock for a given name - * - * @param string $key The Name of the lock - * @param integer $timeout Seconds until we give up - * - * @return boolean Was the lock successful? + * (@inheritdoc) */ public function acquireLock($key, $timeout = 120) { @@ -25,26 +21,25 @@ class DatabaseLockDriver extends AbstractLockDriver do { dba::lock('locks'); - $lock = dba::selectFirst('locks', ['locked', 'pid'], ['name' => $key]); + $lock = dba::selectFirst('locks', ['locked', 'pid'], ['`name` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]); if (DBM::is_result($lock)) { if ($lock['locked']) { - // When the process id isn't used anymore, we can safely claim the lock for us. - if (!posix_kill($lock['pid'], 0)) { - $lock['locked'] = false; - } // We want to lock something that was already locked by us? So we got the lock. if ($lock['pid'] == getmypid()) { $got_lock = true; + $this->markAcquire($key); } } if (!$lock['locked']) { - dba::update('locks', ['locked' => true, 'pid' => getmypid()], ['name' => $key]); + dba::update('locks', ['locked' => true, 'pid' => getmypid(), 'expires' => DateTimeFormat::utc('now + 300seconds')], ['name' => $key]); $got_lock = true; + $this->markAcquire($key); } } else { - dba::insert('locks', ['name' => $key, 'locked' => true, 'pid' => getmypid()]); + dba::insert('locks', ['name' => $key, 'locked' => true, 'pid' => getmypid(), 'expires' => DateTimeFormat::utc('now + 300seconds')]); $got_lock = true; + $this->markAcquire($key); } dba::unlock(); @@ -54,36 +49,42 @@ class DatabaseLockDriver extends AbstractLockDriver } } while (!$got_lock && ((time() - $start) < $timeout)); - $this->markAcquire($key); - return $got_lock; } /** - * @brief Removes a lock if it was set by us - * - * @param string $key Name of the lock - * - * @return mixed + * (@inheritdoc) */ public function releaseLock($key) { - dba::delete('locks', ['locked' => false, 'pid' => 0], ['name' => $key, 'pid' => getmypid()]); + dba::delete('locks', ['name' => $key, 'pid' => getmypid()]); - $this->releaseLock($key); + $this->markRelease($key); return; } /** - * @brief Removes all lock that were set by us - * - * @return void + * (@inheritdoc) */ public function releaseAll() { - dba::delete('locks', ['locked' => false, 'pid' => 0], ['pid' => getmypid()]); + dba::delete('locks', ['pid' => getmypid()]); $this->acquiredLocks = []; } + + /** + * (@inheritdoc) + */ + public function isLocked($key) + { + $lock = dba::selectFirst('locks', ['locked'], ['`name` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]); + + if (DBM::is_result($lock)) { + return $lock['locked'] !== false; + } else { + return false; + } + } } diff --git a/src/Core/Lock/ILockDriver.php b/src/Core/Lock/ILockDriver.php index 8744d757f1..3fbe049d37 100644 --- a/src/Core/Lock/ILockDriver.php +++ b/src/Core/Lock/ILockDriver.php @@ -9,6 +9,14 @@ namespace Friendica\Core\Lock; */ interface ILockDriver { + /** + * @brief Checks, if a key is currently locked to a or my process + * + * @param string $key The name of the lock + * @return bool + */ + public function isLocked($key); + /** * * @brief Acquires a lock for a given name diff --git a/src/Core/Lock/SemaphoreLockDriver.php b/src/Core/Lock/SemaphoreLockDriver.php index 39e3e1d32c..b4439743c8 100644 --- a/src/Core/Lock/SemaphoreLockDriver.php +++ b/src/Core/Lock/SemaphoreLockDriver.php @@ -4,6 +4,8 @@ namespace Friendica\Core\Lock; class SemaphoreLockDriver extends AbstractLockDriver { + private static $semaphore = []; + public function __construct() { if (!function_exists('sem_get')) { @@ -42,10 +44,15 @@ class SemaphoreLockDriver extends AbstractLockDriver */ public function acquireLock($key, $timeout = 120) { - $this->acquiredLocks[$key] = sem_get(self::semaphoreKey($key)); - if ($this->acquiredLocks[$key]) { - return sem_acquire($this->acquiredLocks[$key], ($timeout == 0)); + self::$semaphore[$key] = sem_get(self::semaphoreKey($key)); + if (self::$semaphore[$key]) { + if (sem_acquire(self::$semaphore[$key], ($timeout == 0))) { + $this->markAcquire($key); + return true; + } } + + return false; } /** @@ -57,12 +64,24 @@ class SemaphoreLockDriver extends AbstractLockDriver */ public function releaseLock($key) { - if (empty($this->acquiredLocks[$key])) { + if (empty(self::$semaphore[$key])) { return false; } else { - $success = @sem_release($this->acquiredLocks[$key]); - unset($this->acquiredLocks[$key]); + $success = @sem_release(self::$semaphore[$key]); + unset(self::$semaphore[$key]); + $this->markRelease($key); return $success; } } + + /** + * @brief Checks, if a key is currently locked to a process + * + * @param string $key The name of the lock + * @return bool + */ + public function isLocked($key) + { + return @sem_get(self::$semaphore[$key]) !== false; + } } diff --git a/src/Database/DBStructure.php b/src/Database/DBStructure.php index 8fb2afddb2..b14f31b11f 100644 --- a/src/Database/DBStructure.php +++ b/src/Database/DBStructure.php @@ -4,10 +4,9 @@ */ namespace Friendica\Database; +use dba; use Friendica\Core\Config; use Friendica\Core\L10n; -use Friendica\Database\DBM; -use dba; require_once 'boot.php'; require_once 'include/dba.php'; @@ -1285,9 +1284,11 @@ class DBStructure "name" => ["type" => "varchar(128)", "not null" => "1", "default" => "", "comment" => ""], "locked" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], "pid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => "Process ID"], - ], + "expires" => ["type" => "datetime", "not null" => "1", "default" => NULL_DATE, "comment" => "datetime of cache expiration"], + ], "indexes" => [ "PRIMARY" => ["id"], + "name_expires" => ["name", "expires"] ] ]; $database["mail"] = [ diff --git a/tests/datasets/api.yml b/tests/datasets/api.yml index 9ba5ec387e..14053c3e86 100644 --- a/tests/datasets/api.yml +++ b/tests/datasets/api.yml @@ -14,7 +14,7 @@ user: uid: 42 username: Test user nickname: selfcontact - verified: true + verified: 1 password: $2y$10$DLRNTRmJgKe1cSrFJ5Jb0edCqvXlA9sh/RHdSnfxjbR.04yZRm4Qm theme: frio @@ -24,12 +24,12 @@ contact: uid: 42 name: Self contact nick: selfcontact - self: true + self: 1 nurl: http://localhost/profile/selfcontact url: http://localhost/profile/selfcontact about: User used in tests - pending: false - blocked: false + pending: 0 + blocked: 0 rel: 1 network: dfrn - @@ -39,11 +39,11 @@ contact: # the fallback to api_get_nick() in api_get_user() name: othercontact nick: othercontact - self: false + self: 0 nurl: http://localhost/profile/othercontact url: http://localhost/profile/othercontact - pending: false - blocked: false + pending: 0 + blocked: 0 rel: 0 network: dfrn - @@ -51,150 +51,150 @@ contact: uid: 0 name: Friend contact nick: friendcontact - self: false + self: 0 nurl: http://localhost/profile/friendcontact url: http://localhost/profile/friendcontact - pending: false - blocked: false + pending: 0 + blocked: 0 rel: 2 network: dfrn item: - id: 1 - visible: true + visible: 1 contact-id: 42 author-id: 42 owner-id: 45 uid: 42 verb: http://activitystrea.ms/schema/1.0/post - unseen: true + unseen: 1 body: Parent status parent: 1 author-link: http://localhost/profile/selfcontact - wall: true - starred: true - origin: true + wall: 1 + starred: 1 + origin: 1 allow_cid: '' allow_gid: '' deny_cid: '' deny_gid: '' - id: 2 - visible: true + visible: 1 contact-id: 42 author-id: 42 owner-id: 45 uid: 42 verb: http://activitystrea.ms/schema/1.0/post - unseen: false + unseen: 0 body: Reply parent: 1 author-link: http://localhost/profile/selfcontact - wall: true - starred: false - origin: true + wall: 1 + starred: 0 + origin: 1 - id: 3 - visible: true + visible: 1 contact-id: 43 author-id: 43 owner-id: 42 uid: 42 verb: http://activitystrea.ms/schema/1.0/post - unseen: false + unseen: 0 body: Other user status parent: 3 author-link: http://localhost/profile/othercontact - wall: true - starred: false - origin: true + wall: 1 + starred: 0 + origin: 1 - id: 4 - visible: true + visible: 1 contact-id: 44 author-id: 44 owner-id: 42 uid: 42 verb: http://activitystrea.ms/schema/1.0/post - unseen: false + unseen: 0 body: Friend user reply parent: 1 author-link: http://localhost/profile/othercontact - wall: true - starred: false - origin: true + wall: 1 + starred: 0 + origin: 1 - id: 5 - visible: true + visible: 1 contact-id: 42 author-id: 42 owner-id: 42 uid: 42 verb: http://activitystrea.ms/schema/1.0/post - unseen: false + unseen: 0 body: '[share]Shared status[/share]' parent: 1 author-link: http://localhost/profile/othercontact - wall: true - starred: false - origin: true + wall: 1 + starred: 0 + origin: 1 allow_cid: '' allow_gid: '' deny_cid: '' deny_gid: '' - id: 6 - visible: true + visible: 1 contact-id: 44 author-id: 44 owner-id: 42 uid: 42 verb: http://activitystrea.ms/schema/1.0/post - unseen: false + unseen: 0 body: Friend user status parent: 6 author-link: http://localhost/profile/othercontact - wall: true - starred: false - origin: true + wall: 1 + starred: 0 + origin: 1 thread: - iid: 1 - visible: true + visible: 1 contact-id: 42 author-id: 42 owner-id: 42 uid: 42 - wall: true + wall: 1 - iid: 3 - visible: true + visible: 1 contact-id: 43 author-id: 43 owner-id: 43 uid: 0 - wall: true + wall: 1 - iid: 6 - visible: true + visible: 1 contact-id: 44 author-id: 44 owner-id: 44 uid: 0 - wall: true + wall: 1 group: - id: 1 uid: 42 - visible: true + visible: 1 name: Visible list - id: 2 uid: 42 - visible: false + visible: 0 name: Private list search: diff --git a/tests/src/Core/Lock/CacheLockDriverTest.php b/tests/src/Core/Lock/CacheLockDriverTest.php new file mode 100644 index 0000000000..a089059725 --- /dev/null +++ b/tests/src/Core/Lock/CacheLockDriverTest.php @@ -0,0 +1,27 @@ +cache = new ArrayCache(); + return new CacheLockDriver($this->cache); + } + + public function tearDown() + { + $this->cache->clear(); + parent::tearDown(); + } +} \ No newline at end of file diff --git a/tests/src/Core/Lock/DatabaseLockDriverTest.php b/tests/src/Core/Lock/DatabaseLockDriverTest.php new file mode 100644 index 0000000000..a80ff4c37c --- /dev/null +++ b/tests/src/Core/Lock/DatabaseLockDriverTest.php @@ -0,0 +1,67 @@ +module = 'install'; + + // Create database structure + DBStructure::update(false, true, true); + } else { + $this->markTestSkipped('Could not connect to the database.'); + } + } + + return $this->createDefaultDBConnection(dba::get_db(), getenv('DB')); + } + + /** + * Get dataset to populate the database with. + * @return YamlDataSet + * @see https://phpunit.de/manual/5.7/en/database.html + */ + protected function getDataSet() + { + return new YamlDataSet(__DIR__ . '/../../../datasets/api.yml'); + } + + protected function getInstance() + { + return new DatabaseLockDriver(); + } + + public function tearDown() + { + dba::delete('locks', [ 'id > 0']); + parent::tearDown(); + } +} \ No newline at end of file diff --git a/tests/src/Core/Lock/LockTest.php b/tests/src/Core/Lock/LockTest.php new file mode 100644 index 0000000000..ec7b97a9c7 --- /dev/null +++ b/tests/src/Core/Lock/LockTest.php @@ -0,0 +1,80 @@ +instance = $this->getInstance(); + + // Reusable App object + $this->app = new App(__DIR__.'/../'); + $a = $this->app; + + // Default config + Config::set('config', 'hostname', 'localhost'); + Config::set('system', 'throttle_limit_day', 100); + Config::set('system', 'throttle_limit_week', 100); + Config::set('system', 'throttle_limit_month', 100); + Config::set('system', 'theme', 'system_theme'); + } + + public function testLock() { + $this->instance->acquireLock('foo', 1); + $this->assertTrue($this->instance->isLocked('foo')); + $this->assertFalse($this->instance->isLocked('bar')); + } + + public function testDoubleLock() { + $this->instance->acquireLock('foo', 1); + $this->assertTrue($this->instance->isLocked('foo')); + // We already locked it + $this->assertTrue($this->instance->acquireLock('foo', 1)); + } + + public function testReleaseLock() { + $this->instance->acquireLock('foo', 1); + $this->assertTrue($this->instance->isLocked('foo')); + $this->instance->releaseLock('foo'); + $this->assertFalse($this->instance->isLocked('foo')); + } + + public function testReleaseAll() { + $this->instance->acquireLock('foo', 1); + $this->instance->acquireLock('bar', 1); + $this->instance->acquireLock('#/$%§', 1); + + $this->instance->releaseAll(); + + $this->assertFalse($this->instance->isLocked('foo')); + $this->assertFalse($this->instance->isLocked('bar')); + $this->assertFalse($this->instance->isLocked('#/$%§')); + } + + public function testReleaseAfterUnlock() { + $this->instance->acquireLock('foo', 1); + $this->instance->acquireLock('bar', 1); + $this->instance->acquireLock('#/$%§', 1); + + $this->instance->releaseLock('foo'); + + $this->instance->releaseAll(); + + $this->assertFalse($this->instance->isLocked('bar')); + $this->assertFalse($this->instance->isLocked('#/$%§')); + } +} \ No newline at end of file diff --git a/tests/src/Core/Lock/SemaphoreLockDriverTest.php b/tests/src/Core/Lock/SemaphoreLockDriverTest.php new file mode 100644 index 0000000000..fb7efd6584 --- /dev/null +++ b/tests/src/Core/Lock/SemaphoreLockDriverTest.php @@ -0,0 +1,14 @@ + Date: Wed, 4 Jul 2018 17:55:06 -0400 Subject: [PATCH 46/65] Rename language to lang in test data as well --- tests/ApiTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ApiTest.php b/tests/ApiTest.php index d54d0cc9a3..c8443512c8 100644 --- a/tests/ApiTest.php +++ b/tests/ApiTest.php @@ -635,7 +635,7 @@ class ApiTest extends DatabaseTest */ public function testApiRssExtra() { - $user_info = ['url' => 'user_url', 'language' => 'en']; + $user_info = ['url' => 'user_url', 'lang' => 'en']; $result = api_rss_extra($this->app, [], $user_info); $this->assertEquals($user_info, $result['$user']); $this->assertEquals($user_info['url'], $result['$rss']['alternate']); From 906bb25972bf3f23e6cc3b98a50c0f3fa0990964 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Thu, 5 Jul 2018 07:59:56 +0200 Subject: [PATCH 47/65] code standards / simplifications --- src/Core/Cache/ArrayCache.php | 4 +-- src/Core/Cache/CacheDriverFactory.php | 4 +-- src/Core/Cache/ICacheDriver.php | 10 +++---- src/Core/Cache/IMemoryCacheDriver.php | 10 +++---- src/Core/Cache/MemcacheCacheDriver.php | 3 ++ src/Core/Cache/RedisCacheDriver.php | 21 ++------------ src/Core/Cache/TraitCompareDelete.php | 6 ++-- src/Core/Cache/TraitCompareSet.php | 6 ++-- src/Core/Lock.php | 18 ++---------- src/Core/Lock/AbstractLockDriver.php | 12 ++++---- src/Core/Lock/CacheLockDriver.php | 21 ++++---------- src/Core/Lock/DatabaseLockDriver.php | 4 +-- src/Core/Lock/ILockDriver.php | 12 ++++---- src/Core/Lock/SemaphoreLockDriver.php | 28 ++++--------------- tests/src/Core/Lock/CacheLockDriverTest.php | 2 +- .../src/Core/Lock/DatabaseLockDriverTest.php | 2 +- tests/src/Core/Lock/LockTest.php | 26 ++++++++--------- .../src/Core/Lock/SemaphoreLockDriverTest.php | 2 +- 18 files changed, 70 insertions(+), 121 deletions(-) diff --git a/src/Core/Cache/ArrayCache.php b/src/Core/Cache/ArrayCache.php index d4fe8bc7f7..71610c39df 100644 --- a/src/Core/Cache/ArrayCache.php +++ b/src/Core/Cache/ArrayCache.php @@ -6,7 +6,7 @@ namespace Friendica\Core\Cache; use Friendica\Core\Cache; /** - * @brief Implementation of the IMemoryCacheDriver mainly for testing purpose + * Implementation of the IMemoryCacheDriver mainly for testing purpose * * Class ArrayCache * @@ -80,4 +80,4 @@ class ArrayCache implements IMemoryCacheDriver return false; } } -} \ No newline at end of file +} diff --git a/src/Core/Cache/CacheDriverFactory.php b/src/Core/Cache/CacheDriverFactory.php index 45cc17a52f..8fbdc1549e 100644 --- a/src/Core/Cache/CacheDriverFactory.php +++ b/src/Core/Cache/CacheDriverFactory.php @@ -9,12 +9,12 @@ use Friendica\Core\Config; * * @package Friendica\Core\Cache * - * @brief A basic class to generate a CacheDriver + * A basic class to generate a CacheDriver */ class CacheDriverFactory { /** - * @brief This method creates a CacheDriver for the given cache driver name + * This method creates a CacheDriver for the given cache driver name * * @param string $driver The name of the cache driver * @return ICacheDriver The instance of the CacheDriver diff --git a/src/Core/Cache/ICacheDriver.php b/src/Core/Cache/ICacheDriver.php index ff329f34eb..ced7b4e216 100644 --- a/src/Core/Cache/ICacheDriver.php +++ b/src/Core/Cache/ICacheDriver.php @@ -12,7 +12,7 @@ use Friendica\Core\Cache; interface ICacheDriver { /** - * @brief Fetches cached data according to the key + * Fetches cached data according to the key * * @param string $key The key to the cached data * @@ -21,18 +21,18 @@ interface ICacheDriver public function get($key); /** - * @brief Stores data in the cache identified by the key. The input $value can have multiple formats. + * Stores data in the cache identified by the key. The input $value can have multiple formats. * * @param string $key The cache key * @param mixed $value The value to store - * @param integer $ttl The cache lifespan, must be one of the Cache constants + * @param integer $ttl The cache lifespan, must be one of the Cache constants * * @return bool */ public function set($key, $value, $ttl = Cache::FIVE_MINUTES); /** - * @brief Delete a key from the cache + * Delete a key from the cache * * @param string $key The cache key * @@ -41,7 +41,7 @@ interface ICacheDriver public function delete($key); /** - * @brief Remove outdated data from the cache + * Remove outdated data from the cache * * @return bool */ diff --git a/src/Core/Cache/IMemoryCacheDriver.php b/src/Core/Cache/IMemoryCacheDriver.php index 7843ca7b5f..a50e2d1d48 100644 --- a/src/Core/Cache/IMemoryCacheDriver.php +++ b/src/Core/Cache/IMemoryCacheDriver.php @@ -4,7 +4,7 @@ namespace Friendica\Core\Cache; use Friendica\Core\Cache; /** - * @brief This interface defines methods for Memory-Caches only + * This interface defines methods for Memory-Caches only * * Interface IMemoryCacheDriver * @@ -13,7 +13,7 @@ use Friendica\Core\Cache; interface IMemoryCacheDriver extends ICacheDriver { /** - * @brief Sets a value if it's not already stored + * Sets a value if it's not already stored * * @param string $key The cache key * @param mixed $value The old value we know from the cache @@ -23,7 +23,7 @@ interface IMemoryCacheDriver extends ICacheDriver public function add($key, $value, $ttl = Cache::FIVE_MINUTES); /** - * @brief Compares if the old value is set and sets the new value + * Compares if the old value is set and sets the new value * * @param string $key The cache key * @param mixed $oldValue The old value we know from the cache @@ -35,11 +35,11 @@ interface IMemoryCacheDriver extends ICacheDriver public function compareSet($key, $oldValue, $newValue, $ttl = Cache::FIVE_MINUTES); /** - * @brief Compares if the old value is set and removes it + * Compares if the old value is set and removes it * * @param string $key The cache key * @param mixed $value The old value we know and want to delete * @return bool */ public function compareDelete($key, $value); -} \ No newline at end of file +} diff --git a/src/Core/Cache/MemcacheCacheDriver.php b/src/Core/Cache/MemcacheCacheDriver.php index 0b1ca3cec9..8eb45d907e 100644 --- a/src/Core/Cache/MemcacheCacheDriver.php +++ b/src/Core/Cache/MemcacheCacheDriver.php @@ -90,6 +90,9 @@ class MemcacheCacheDriver extends BaseObject implements IMemoryCacheDriver return $this->memcache->delete($key); } + /** + * (@inheritdoc) + */ public function clear() { return $this->memcache->flush(); diff --git a/src/Core/Cache/RedisCacheDriver.php b/src/Core/Cache/RedisCacheDriver.php index d23fa2697b..25c18aa6b6 100644 --- a/src/Core/Cache/RedisCacheDriver.php +++ b/src/Core/Cache/RedisCacheDriver.php @@ -84,12 +84,7 @@ class RedisCacheDriver extends BaseObject implements IMemoryCacheDriver /** - * @brief Sets a value if it's not already stored - * - * @param string $key The cache key - * @param mixed $value The old value we know from the cache - * @param int $ttl The cache lifespan, must be one of the Cache constants - * @return bool + * (@inheritdoc) */ public function add($key, $value, $ttl = Cache::FIVE_MINUTES) { @@ -101,13 +96,7 @@ class RedisCacheDriver extends BaseObject implements IMemoryCacheDriver } /** - * @brief Compares if the old value is set and sets the new value - * - * @param string $key The cache key - * @param mixed $oldValue The old value we know - * @param mixed $newValue The new value we want to set - * @param int $ttl The cache lifespan, must be one of the Cache constants - * @return bool + * (@inheritdoc) */ public function compareSet($key, $oldValue, $newValue, $ttl = Cache::FIVE_MINUTES) { @@ -133,11 +122,7 @@ class RedisCacheDriver extends BaseObject implements IMemoryCacheDriver return false; } /** - * @brief Compares if the old value is set and removes it - * - * @param string $key The cache key - * @param mixed $value The old value we know and want to delete - * @return bool + * (@inheritdoc) */ public function compareDelete($key, $value) { diff --git a/src/Core/Cache/TraitCompareDelete.php b/src/Core/Cache/TraitCompareDelete.php index 898e39aecc..ef59f69cd1 100644 --- a/src/Core/Cache/TraitCompareDelete.php +++ b/src/Core/Cache/TraitCompareDelete.php @@ -7,7 +7,7 @@ use Friendica\Core\Cache; /** * Trait TraitCompareSetDelete * - * @brief This Trait is to compensate non native "exclusive" sets/deletes in caches + * This Trait is to compensate non native "exclusive" sets/deletes in caches * * @package Friendica\Core\Cache */ @@ -22,7 +22,7 @@ trait TraitCompareDelete abstract public function add($key, $value, $ttl = Cache::FIVE_MINUTES); /** - * @brief NonNative - Compares if the old value is set and removes it + * NonNative - Compares if the old value is set and removes it * * @param string $key The cache key * @param mixed $value The old value we know and want to delete @@ -42,4 +42,4 @@ trait TraitCompareDelete return false; } } -} \ No newline at end of file +} diff --git a/src/Core/Cache/TraitCompareSet.php b/src/Core/Cache/TraitCompareSet.php index 55193b7567..77a6028355 100644 --- a/src/Core/Cache/TraitCompareSet.php +++ b/src/Core/Cache/TraitCompareSet.php @@ -7,7 +7,7 @@ use Friendica\Core\Cache; /** * Trait TraitCompareSetDelete * - * @brief This Trait is to compensate non native "exclusive" sets/deletes in caches + * This Trait is to compensate non native "exclusive" sets/deletes in caches * * @package Friendica\Core\Cache */ @@ -22,7 +22,7 @@ trait TraitCompareSet abstract public function add($key, $value, $ttl = Cache::FIVE_MINUTES); /** - * @brief NonNative - Compares if the old value is set and sets the new value + * NonNative - Compares if the old value is set and sets the new value * * @param string $key The cache key * @param mixed $oldValue The old value we know from the cache @@ -45,4 +45,4 @@ trait TraitCompareSet return false; } } -} \ No newline at end of file +} diff --git a/src/Core/Lock.php b/src/Core/Lock.php index 7235c64a98..47a1f9b4fe 100644 --- a/src/Core/Lock.php +++ b/src/Core/Lock.php @@ -29,21 +29,9 @@ class Lock try { switch ($lock_driver) { case 'memcache': - $cache_driver = CacheDriverFactory::create('memcache'); - if ($cache_driver instanceof IMemoryCacheDriver) { - self::$driver = new Lock\CacheLockDriver($cache_driver); - } - break; - case 'memcached': - $cache_driver = CacheDriverFactory::create('memcached'); - if ($cache_driver instanceof IMemoryCacheDriver) { - self::$driver = new Lock\CacheLockDriver($cache_driver); - } - break; - case 'redis': - $cache_driver = CacheDriverFactory::create('redis'); + $cache_driver = CacheDriverFactory::create($lock_driver); if ($cache_driver instanceof IMemoryCacheDriver) { self::$driver = new Lock\CacheLockDriver($cache_driver); } @@ -129,7 +117,7 @@ class Lock */ public static function acquireLock($key, $timeout = 120) { - return self::getDriver()->acquireLock($key, $timeout); + return self::getDriver()->acquire($key, $timeout); } /** @@ -140,7 +128,7 @@ class Lock */ public static function releaseLock($key) { - return self::getDriver()->releaseLock($key); + return self::getDriver()->release($key); } /** diff --git a/src/Core/Lock/AbstractLockDriver.php b/src/Core/Lock/AbstractLockDriver.php index 09549c50bf..53597d45fc 100644 --- a/src/Core/Lock/AbstractLockDriver.php +++ b/src/Core/Lock/AbstractLockDriver.php @@ -8,7 +8,7 @@ use Friendica\BaseObject; * * @package Friendica\Core\Lock * - * @brief Basic class for Locking with common functions (local acquired locks, releaseAll, ..) + * Basic class for Locking with common functions (local acquired locks, releaseAll, ..) */ abstract class AbstractLockDriver extends BaseObject implements ILockDriver { @@ -18,7 +18,7 @@ abstract class AbstractLockDriver extends BaseObject implements ILockDriver protected $acquiredLocks = []; /** - * @brief Check if we've locally acquired a lock + * Check if we've locally acquired a lock * * @param string key The Name of the lock * @return bool Returns true if the lock is set @@ -28,7 +28,7 @@ abstract class AbstractLockDriver extends BaseObject implements ILockDriver } /** - * @brief Mark a locally acquired lock + * Mark a locally acquired lock * * @param string $key The Name of the lock */ @@ -37,7 +37,7 @@ abstract class AbstractLockDriver extends BaseObject implements ILockDriver } /** - * @brief Mark a release of a locally acquired lock + * Mark a release of a locally acquired lock * * @param string $key The Name of the lock */ @@ -46,13 +46,13 @@ abstract class AbstractLockDriver extends BaseObject implements ILockDriver } /** - * @brief Releases all lock that were set by us + * Releases all lock that were set by us * * @return void */ public function releaseAll() { foreach ($this->acquiredLocks as $acquiredLock => $hasLock) { - $this->releaseLock($acquiredLock); + $this->release($acquiredLock); } } } diff --git a/src/Core/Lock/CacheLockDriver.php b/src/Core/Lock/CacheLockDriver.php index 13d912c1e2..57627acecf 100644 --- a/src/Core/Lock/CacheLockDriver.php +++ b/src/Core/Lock/CacheLockDriver.php @@ -22,15 +22,9 @@ class CacheLockDriver extends AbstractLockDriver } /** - * - * @brief Sets a lock for a given name - * - * @param string $key The Name of the lock - * @param integer $timeout Seconds until we give up - * - * @return boolean Was the lock successful? + * (@inheritdoc) */ - public function acquireLock($key, $timeout = 120) + public function acquire($key, $timeout = 120) { $got_lock = false; $start = time(); @@ -64,11 +58,9 @@ class CacheLockDriver extends AbstractLockDriver } /** - * @brief Removes a lock if it was set by us - * - * @param string $key Name of the lock + * (@inheritdoc) */ - public function releaseLock($key) + public function release($key) { $cachekey = self::getCacheKey($key); @@ -77,10 +69,7 @@ class CacheLockDriver extends AbstractLockDriver } /** - * @brief Checks, if a key is currently locked to a process - * - * @param string $key The name of the lock - * @return bool + * (@inheritdoc) */ public function isLocked($key) { diff --git a/src/Core/Lock/DatabaseLockDriver.php b/src/Core/Lock/DatabaseLockDriver.php index 6f4b942a4d..8f8e174214 100644 --- a/src/Core/Lock/DatabaseLockDriver.php +++ b/src/Core/Lock/DatabaseLockDriver.php @@ -14,7 +14,7 @@ class DatabaseLockDriver extends AbstractLockDriver /** * (@inheritdoc) */ - public function acquireLock($key, $timeout = 120) + public function acquire($key, $timeout = 120) { $got_lock = false; $start = time(); @@ -55,7 +55,7 @@ class DatabaseLockDriver extends AbstractLockDriver /** * (@inheritdoc) */ - public function releaseLock($key) + public function release($key) { dba::delete('locks', ['name' => $key, 'pid' => getmypid()]); diff --git a/src/Core/Lock/ILockDriver.php b/src/Core/Lock/ILockDriver.php index 3fbe049d37..af8a1d56ae 100644 --- a/src/Core/Lock/ILockDriver.php +++ b/src/Core/Lock/ILockDriver.php @@ -10,7 +10,7 @@ namespace Friendica\Core\Lock; interface ILockDriver { /** - * @brief Checks, if a key is currently locked to a or my process + * Checks, if a key is currently locked to a or my process * * @param string $key The name of the lock * @return bool @@ -19,26 +19,26 @@ interface ILockDriver /** * - * @brief Acquires a lock for a given name + * Acquires a lock for a given name * * @param string $key The Name of the lock * @param integer $timeout Seconds until we give up * * @return boolean Was the lock successful? */ - public function acquireLock($key, $timeout = 120); + public function acquire($key, $timeout = 120); /** - * @brief Releases a lock if it was set by us + * Releases a lock if it was set by us * * @param string $key The Name of the lock * * @return void */ - public function releaseLock($key); + public function release($key); /** - * @brief Releases all lock that were set by us + * Releases all lock that were set by us * * @return void */ diff --git a/src/Core/Lock/SemaphoreLockDriver.php b/src/Core/Lock/SemaphoreLockDriver.php index b4439743c8..250a75fbfe 100644 --- a/src/Core/Lock/SemaphoreLockDriver.php +++ b/src/Core/Lock/SemaphoreLockDriver.php @@ -14,11 +14,7 @@ class SemaphoreLockDriver extends AbstractLockDriver } /** - * @brief Creates a semaphore key - * - * @param string $key Name of the lock - * - * @return integer the semaphore key + * (@inheritdoc) */ private static function semaphoreKey($key) { @@ -35,14 +31,9 @@ class SemaphoreLockDriver extends AbstractLockDriver /** * - * @brief Sets a lock for a given name - * - * @param string $key The Name of the lock - * @param integer $timeout Seconds until we give up - * - * @return boolean Was the lock successful? + * (@inheritdoc) */ - public function acquireLock($key, $timeout = 120) + public function acquire($key, $timeout = 120) { self::$semaphore[$key] = sem_get(self::semaphoreKey($key)); if (self::$semaphore[$key]) { @@ -56,13 +47,9 @@ class SemaphoreLockDriver extends AbstractLockDriver } /** - * @brief Removes a lock if it was set by us - * - * @param string $key Name of the lock - * - * @return mixed + * (@inheritdoc) */ - public function releaseLock($key) + public function release($key) { if (empty(self::$semaphore[$key])) { return false; @@ -75,10 +62,7 @@ class SemaphoreLockDriver extends AbstractLockDriver } /** - * @brief Checks, if a key is currently locked to a process - * - * @param string $key The name of the lock - * @return bool + * (@inheritdoc) */ public function isLocked($key) { diff --git a/tests/src/Core/Lock/CacheLockDriverTest.php b/tests/src/Core/Lock/CacheLockDriverTest.php index a089059725..b39000e119 100644 --- a/tests/src/Core/Lock/CacheLockDriverTest.php +++ b/tests/src/Core/Lock/CacheLockDriverTest.php @@ -1,6 +1,6 @@ instance->acquireLock('foo', 1); + $this->instance->acquire('foo', 1); $this->assertTrue($this->instance->isLocked('foo')); $this->assertFalse($this->instance->isLocked('bar')); } public function testDoubleLock() { - $this->instance->acquireLock('foo', 1); + $this->instance->acquire('foo', 1); $this->assertTrue($this->instance->isLocked('foo')); // We already locked it - $this->assertTrue($this->instance->acquireLock('foo', 1)); + $this->assertTrue($this->instance->acquire('foo', 1)); } public function testReleaseLock() { - $this->instance->acquireLock('foo', 1); + $this->instance->acquire('foo', 1); $this->assertTrue($this->instance->isLocked('foo')); - $this->instance->releaseLock('foo'); + $this->instance->release('foo'); $this->assertFalse($this->instance->isLocked('foo')); } public function testReleaseAll() { - $this->instance->acquireLock('foo', 1); - $this->instance->acquireLock('bar', 1); - $this->instance->acquireLock('#/$%§', 1); + $this->instance->acquire('foo', 1); + $this->instance->acquire('bar', 1); + $this->instance->acquire('#/$%§', 1); $this->instance->releaseAll(); @@ -66,11 +66,11 @@ abstract class LockTest extends TestCase } public function testReleaseAfterUnlock() { - $this->instance->acquireLock('foo', 1); - $this->instance->acquireLock('bar', 1); - $this->instance->acquireLock('#/$%§', 1); + $this->instance->acquire('foo', 1); + $this->instance->acquire('bar', 1); + $this->instance->acquire('#/$%§', 1); - $this->instance->releaseLock('foo'); + $this->instance->release('foo'); $this->instance->releaseAll(); diff --git a/tests/src/Core/Lock/SemaphoreLockDriverTest.php b/tests/src/Core/Lock/SemaphoreLockDriverTest.php index fb7efd6584..0fcf789e61 100644 --- a/tests/src/Core/Lock/SemaphoreLockDriverTest.php +++ b/tests/src/Core/Lock/SemaphoreLockDriverTest.php @@ -1,6 +1,6 @@ Date: Thu, 5 Jul 2018 20:57:31 +0200 Subject: [PATCH 48/65] Fixings - fixed test for semaphore - fixed some issues - changed namespace in Tests back to "src/" - changed namings --- src/Core/Cache/MemcachedCacheDriver.php | 2 +- src/Core/Cache/RedisCacheDriver.php | 2 +- src/Core/Lock.php | 14 ++++------ src/Core/Lock/AbstractLockDriver.php | 2 +- src/Core/Lock/CacheLockDriver.php | 4 +-- src/Core/Lock/DatabaseLockDriver.php | 4 +-- src/Core/Lock/ILockDriver.php | 4 +-- src/Core/Lock/SemaphoreLockDriver.php | 8 +++--- src/Core/Worker.php | 22 ++++++--------- src/Model/Item.php | 12 +++----- src/Protocol/OStatus.php | 10 +++---- tests/src/Core/Lock/CacheLockDriverTest.php | 2 +- .../src/Core/Lock/DatabaseLockDriverTest.php | 2 +- tests/src/Core/Lock/LockTest.php | 28 +++++++++---------- .../src/Core/Lock/SemaphoreLockDriverTest.php | 16 +++++++++-- 15 files changed, 67 insertions(+), 65 deletions(-) diff --git a/src/Core/Cache/MemcachedCacheDriver.php b/src/Core/Cache/MemcachedCacheDriver.php index 9c860711f8..dda36ba19c 100644 --- a/src/Core/Cache/MemcachedCacheDriver.php +++ b/src/Core/Cache/MemcachedCacheDriver.php @@ -16,7 +16,7 @@ class MemcachedCacheDriver extends BaseObject implements IMemoryCacheDriver use TraitCompareDelete; /** - * @var Memcached + * @var \Memcached */ private $memcached; diff --git a/src/Core/Cache/RedisCacheDriver.php b/src/Core/Cache/RedisCacheDriver.php index 25c18aa6b6..735418b2d2 100644 --- a/src/Core/Cache/RedisCacheDriver.php +++ b/src/Core/Cache/RedisCacheDriver.php @@ -14,7 +14,7 @@ use Friendica\Core\Cache; class RedisCacheDriver extends BaseObject implements IMemoryCacheDriver { /** - * @var Redis + * @var \Redis */ private $redis; diff --git a/src/Core/Lock.php b/src/Core/Lock.php index 47a1f9b4fe..9892f1f4e4 100644 --- a/src/Core/Lock.php +++ b/src/Core/Lock.php @@ -1,7 +1,5 @@ acquire($key, $timeout); + return self::getDriver()->acquireLock($key, $timeout); } /** * @brief Releases a lock if it was set by us * * @param string $key Name of the lock - * @return mixed + * @return void */ - public static function releaseLock($key) + public static function release($key) { - return self::getDriver()->release($key); + self::getDriver()->releaseLock($key); } /** diff --git a/src/Core/Lock/AbstractLockDriver.php b/src/Core/Lock/AbstractLockDriver.php index 53597d45fc..033d6f356e 100644 --- a/src/Core/Lock/AbstractLockDriver.php +++ b/src/Core/Lock/AbstractLockDriver.php @@ -52,7 +52,7 @@ abstract class AbstractLockDriver extends BaseObject implements ILockDriver */ public function releaseAll() { foreach ($this->acquiredLocks as $acquiredLock => $hasLock) { - $this->release($acquiredLock); + $this->releaseLock($acquiredLock); } } } diff --git a/src/Core/Lock/CacheLockDriver.php b/src/Core/Lock/CacheLockDriver.php index 57627acecf..2dd6f3fad9 100644 --- a/src/Core/Lock/CacheLockDriver.php +++ b/src/Core/Lock/CacheLockDriver.php @@ -24,7 +24,7 @@ class CacheLockDriver extends AbstractLockDriver /** * (@inheritdoc) */ - public function acquire($key, $timeout = 120) + public function acquireLock($key, $timeout = 120) { $got_lock = false; $start = time(); @@ -60,7 +60,7 @@ class CacheLockDriver extends AbstractLockDriver /** * (@inheritdoc) */ - public function release($key) + public function releaseLock($key) { $cachekey = self::getCacheKey($key); diff --git a/src/Core/Lock/DatabaseLockDriver.php b/src/Core/Lock/DatabaseLockDriver.php index 8f8e174214..6f4b942a4d 100644 --- a/src/Core/Lock/DatabaseLockDriver.php +++ b/src/Core/Lock/DatabaseLockDriver.php @@ -14,7 +14,7 @@ class DatabaseLockDriver extends AbstractLockDriver /** * (@inheritdoc) */ - public function acquire($key, $timeout = 120) + public function acquireLock($key, $timeout = 120) { $got_lock = false; $start = time(); @@ -55,7 +55,7 @@ class DatabaseLockDriver extends AbstractLockDriver /** * (@inheritdoc) */ - public function release($key) + public function releaseLock($key) { dba::delete('locks', ['name' => $key, 'pid' => getmypid()]); diff --git a/src/Core/Lock/ILockDriver.php b/src/Core/Lock/ILockDriver.php index af8a1d56ae..cd54cc03c3 100644 --- a/src/Core/Lock/ILockDriver.php +++ b/src/Core/Lock/ILockDriver.php @@ -26,7 +26,7 @@ interface ILockDriver * * @return boolean Was the lock successful? */ - public function acquire($key, $timeout = 120); + public function acquireLock($key, $timeout = 120); /** * Releases a lock if it was set by us @@ -35,7 +35,7 @@ interface ILockDriver * * @return void */ - public function release($key); + public function releaseLock($key); /** * Releases all lock that were set by us diff --git a/src/Core/Lock/SemaphoreLockDriver.php b/src/Core/Lock/SemaphoreLockDriver.php index 250a75fbfe..d032d46cc6 100644 --- a/src/Core/Lock/SemaphoreLockDriver.php +++ b/src/Core/Lock/SemaphoreLockDriver.php @@ -20,7 +20,7 @@ class SemaphoreLockDriver extends AbstractLockDriver { $temp = get_temppath(); - $file = $temp.'/'.$key.'.sem'; + $file = $temp . '/' . $key . '.sem'; if (!file_exists($file)) { file_put_contents($file, $key); @@ -33,7 +33,7 @@ class SemaphoreLockDriver extends AbstractLockDriver * * (@inheritdoc) */ - public function acquire($key, $timeout = 120) + public function acquireLock($key, $timeout = 120) { self::$semaphore[$key] = sem_get(self::semaphoreKey($key)); if (self::$semaphore[$key]) { @@ -49,7 +49,7 @@ class SemaphoreLockDriver extends AbstractLockDriver /** * (@inheritdoc) */ - public function release($key) + public function releaseLock($key) { if (empty(self::$semaphore[$key])) { return false; @@ -66,6 +66,6 @@ class SemaphoreLockDriver extends AbstractLockDriver */ public function isLocked($key) { - return @sem_get(self::$semaphore[$key]) !== false; + return isset(self::$semaphore[$key]); } } diff --git a/src/Core/Worker.php b/src/Core/Worker.php index cbf2ae8bd9..c4c91bbf8b 100644 --- a/src/Core/Worker.php +++ b/src/Core/Worker.php @@ -4,15 +4,11 @@ */ namespace Friendica\Core; -use Friendica\Core\Addon; -use Friendica\Core\Config; -use Friendica\Core\System; -use Friendica\Core\Lock; +use dba; use Friendica\Database\DBM; use Friendica\Model\Process; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; -use dba; require_once 'include/dba.php'; @@ -108,16 +104,16 @@ class Worker } // If possible we will fetch new jobs for this worker - if (!$refetched && Lock::acquireLock('worker_process', 0)) { + if (!$refetched && Lock::acquire('worker_process', 0)) { $stamp = (float)microtime(true); $refetched = self::findWorkerProcesses($passing_slow); self::$db_duration += (microtime(true) - $stamp); - Lock::releaseLock('worker_process'); + Lock::release('worker_process'); } } // To avoid the quitting of multiple workers only one worker at a time will execute the check - if (Lock::acquireLock('worker', 0)) { + if (Lock::acquire('worker', 0)) { $stamp = (float)microtime(true); // Count active workers and compare them with a maximum value that depends on the load if (self::tooMuchWorkers()) { @@ -130,7 +126,7 @@ class Worker logger('Memory limit reached, quitting.', LOGGER_DEBUG); return; } - Lock::releaseLock('worker'); + Lock::release('worker'); self::$db_duration += (microtime(true) - $stamp); } @@ -883,7 +879,7 @@ class Worker dba::close($r); $stamp = (float)microtime(true); - if (!Lock::acquireLock('worker_process')) { + if (!Lock::acquire('worker_process')) { return false; } self::$lock_duration = (microtime(true) - $stamp); @@ -892,7 +888,7 @@ class Worker $found = self::findWorkerProcesses($passing_slow); self::$db_duration += (microtime(true) - $stamp); - Lock::releaseLock('worker_process'); + Lock::release('worker_process'); if ($found) { $r = dba::select('workerqueue', [], ['pid' => getmypid(), 'done' => false]); @@ -1097,13 +1093,13 @@ class Worker } // If there is a lock then we don't have to check for too much worker - if (!Lock::acquireLock('worker', 0)) { + if (!Lock::acquire('worker', 0)) { return true; } // If there are already enough workers running, don't fork another one $quit = self::tooMuchWorkers(); - Lock::releaseLock('worker'); + Lock::release('worker'); if ($quit) { return true; diff --git a/src/Model/Item.php b/src/Model/Item.php index ac53bb0220..d31d7c1323 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -6,26 +6,22 @@ namespace Friendica\Model; +use dba; use Friendica\BaseObject; use Friendica\Content\Text; use Friendica\Core\Addon; use Friendica\Core\Config; use Friendica\Core\L10n; +use Friendica\Core\Lock; use Friendica\Core\PConfig; use Friendica\Core\System; use Friendica\Core\Worker; use Friendica\Database\DBM; -use Friendica\Model\Contact; -use Friendica\Model\Conversation; -use Friendica\Model\Group; -use Friendica\Model\Term; use Friendica\Object\Image; use Friendica\Protocol\Diaspora; use Friendica\Protocol\OStatus; use Friendica\Util\DateTimeFormat; use Friendica\Util\XML; -use Friendica\Util\Lock; -use dba; use Text_LanguageDetect; require_once 'boot.php'; @@ -1595,7 +1591,7 @@ class Item extends BaseObject } // To avoid timing problems, we are using locks. - $locked = Lock::set('item_insert_content'); + $locked = Lock::acquire('item_insert_content'); if (!$locked) { logger("Couldn't acquire lock for URI " . $item['uri'] . " - proceeding anyway."); } @@ -1615,7 +1611,7 @@ class Item extends BaseObject logger('Could not insert content for URI ' . $item['uri'] . ' - trying asynchronously'); } if ($locked) { - Lock::remove('item_insert_content'); + Lock::release('item_insert_content'); } } diff --git a/src/Protocol/OStatus.php b/src/Protocol/OStatus.php index d94f44814f..dadc19dcca 100644 --- a/src/Protocol/OStatus.php +++ b/src/Protocol/OStatus.php @@ -4,6 +4,9 @@ */ namespace Friendica\Protocol; +use dba; +use DOMDocument; +use DOMXPath; use Friendica\Content\Text\BBCode; use Friendica\Content\Text\HTML; use Friendica\Core\Cache; @@ -22,9 +25,6 @@ use Friendica\Object\Image; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; use Friendica\Util\XML; -use dba; -use DOMDocument; -use DOMXPath; require_once 'include/dba.php'; require_once 'include/items.php'; @@ -513,9 +513,9 @@ class OStatus logger("Item with uri ".$item["uri"]." is from a blocked contact.", LOGGER_DEBUG); } else { // We are having duplicated entries. Hopefully this solves it. - if (Lock::acquireLock('ostatus_process_item_insert')) { + if (Lock::acquire('ostatus_process_item_insert')) { $ret = Item::insert($item); - Lock::releaseLock('ostatus_process_item_insert'); + Lock::release('ostatus_process_item_insert'); logger("Item with uri ".$item["uri"]." for user ".$importer["uid"].' stored. Return value: '.$ret); } else { $ret = Item::insert($item); diff --git a/tests/src/Core/Lock/CacheLockDriverTest.php b/tests/src/Core/Lock/CacheLockDriverTest.php index b39000e119..a089059725 100644 --- a/tests/src/Core/Lock/CacheLockDriverTest.php +++ b/tests/src/Core/Lock/CacheLockDriverTest.php @@ -1,6 +1,6 @@ instance->acquire('foo', 1); + $this->instance->acquireLock('foo', 1); $this->assertTrue($this->instance->isLocked('foo')); $this->assertFalse($this->instance->isLocked('bar')); } public function testDoubleLock() { - $this->instance->acquire('foo', 1); + $this->instance->acquireLock('foo', 1); $this->assertTrue($this->instance->isLocked('foo')); // We already locked it - $this->assertTrue($this->instance->acquire('foo', 1)); + $this->assertTrue($this->instance->acquireLock('foo', 1)); } public function testReleaseLock() { - $this->instance->acquire('foo', 1); + $this->instance->acquireLock('foo', 1); $this->assertTrue($this->instance->isLocked('foo')); - $this->instance->release('foo'); + $this->instance->releaseLock('foo'); $this->assertFalse($this->instance->isLocked('foo')); } public function testReleaseAll() { - $this->instance->acquire('foo', 1); - $this->instance->acquire('bar', 1); - $this->instance->acquire('#/$%§', 1); + $this->instance->acquireLock('foo', 1); + $this->instance->acquireLock('bar', 1); + $this->instance->acquireLock('nice', 1); $this->instance->releaseAll(); $this->assertFalse($this->instance->isLocked('foo')); $this->assertFalse($this->instance->isLocked('bar')); - $this->assertFalse($this->instance->isLocked('#/$%§')); + $this->assertFalse($this->instance->isLocked('nice')); } public function testReleaseAfterUnlock() { - $this->instance->acquire('foo', 1); - $this->instance->acquire('bar', 1); - $this->instance->acquire('#/$%§', 1); + $this->instance->acquireLock('foo', 1); + $this->instance->acquireLock('bar', 1); + $this->instance->acquireLock('nice', 1); - $this->instance->release('foo'); + $this->instance->releaseLock('foo'); $this->instance->releaseAll(); diff --git a/tests/src/Core/Lock/SemaphoreLockDriverTest.php b/tests/src/Core/Lock/SemaphoreLockDriverTest.php index 0fcf789e61..56c96458f2 100644 --- a/tests/src/Core/Lock/SemaphoreLockDriverTest.php +++ b/tests/src/Core/Lock/SemaphoreLockDriverTest.php @@ -1,14 +1,26 @@ semaphoreLockDriver = new SemaphoreLockDriver(); + return $this->semaphoreLockDriver; + } + + public function tearDown() + { + $this->semaphoreLockDriver->releaseAll(); + parent::tearDown(); } } \ No newline at end of file From 34cea93a8be03690d8515039c61affc9f328a02b Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Thu, 5 Jul 2018 21:47:52 +0200 Subject: [PATCH 49/65] Bugfixings for Cache-Lock - used wrong cachekey in set - therefore added an abstraction to avoid wrong key concatenation - forgot to increase the db-version to 1275 --- boot.php | 2 +- src/Core/Cache/AbstractCacheDriver.php | 23 ++++++++++++++++++ src/Core/Cache/ArrayCache.php | 2 +- src/Core/Cache/MemcacheCacheDriver.php | 18 ++++++++------ src/Core/Cache/MemcachedCacheDriver.php | 20 +++++++++------- src/Core/Cache/RedisCacheDriver.php | 32 +++++++++++++++---------- src/Core/Lock/CacheLockDriver.php | 10 ++++---- 7 files changed, 72 insertions(+), 35 deletions(-) create mode 100644 src/Core/Cache/AbstractCacheDriver.php diff --git a/boot.php b/boot.php index a4588b3f73..249fd9a891 100644 --- a/boot.php +++ b/boot.php @@ -41,7 +41,7 @@ define('FRIENDICA_PLATFORM', 'Friendica'); define('FRIENDICA_CODENAME', 'The Tazmans Flax-lily'); define('FRIENDICA_VERSION', '2018.08-dev'); define('DFRN_PROTOCOL_VERSION', '2.23'); -define('DB_UPDATE_VERSION', 1274); +define('DB_UPDATE_VERSION', 1275); define('NEW_UPDATE_ROUTINE_VERSION', 1170); /** diff --git a/src/Core/Cache/AbstractCacheDriver.php b/src/Core/Cache/AbstractCacheDriver.php new file mode 100644 index 0000000000..6974dff1bd --- /dev/null +++ b/src/Core/Cache/AbstractCacheDriver.php @@ -0,0 +1,23 @@ +get_hostname() . ":" . $key; + } +} \ No newline at end of file diff --git a/src/Core/Cache/ArrayCache.php b/src/Core/Cache/ArrayCache.php index 71610c39df..714021c723 100644 --- a/src/Core/Cache/ArrayCache.php +++ b/src/Core/Cache/ArrayCache.php @@ -12,7 +12,7 @@ use Friendica\Core\Cache; * * @package Friendica\Core\Cache */ -class ArrayCache implements IMemoryCacheDriver +class ArrayCache extends AbstractCacheDriver { use TraitCompareDelete; diff --git a/src/Core/Cache/MemcacheCacheDriver.php b/src/Core/Cache/MemcacheCacheDriver.php index 8eb45d907e..9c16d55312 100644 --- a/src/Core/Cache/MemcacheCacheDriver.php +++ b/src/Core/Cache/MemcacheCacheDriver.php @@ -2,7 +2,6 @@ namespace Friendica\Core\Cache; -use Friendica\BaseObject; use Friendica\Core\Cache; /** @@ -10,7 +9,7 @@ use Friendica\Core\Cache; * * @author Hypolite Petovan */ -class MemcacheCacheDriver extends BaseObject implements IMemoryCacheDriver +class MemcacheCacheDriver extends AbstractCacheDriver { use TraitCompareSet; use TraitCompareDelete; @@ -39,9 +38,10 @@ class MemcacheCacheDriver extends BaseObject implements IMemoryCacheDriver public function get($key) { $return = null; + $cachekey = $this->getCacheKey($key); // We fetch with the hostname as key to avoid problems with other applications - $cached = $this->memcache->get(self::getApp()->get_hostname() . ':' . $key); + $cached = $this->memcache->get($cachekey); // @see http://php.net/manual/en/memcache.get.php#84275 if (is_bool($cached) || is_double($cached) || is_long($cached)) { @@ -65,17 +65,19 @@ class MemcacheCacheDriver extends BaseObject implements IMemoryCacheDriver */ public function set($key, $value, $ttl = Cache::FIVE_MINUTES) { + $cachekey = $this->getCacheKey($key); + // We store with the hostname as key to avoid problems with other applications if ($ttl > 0) { return $this->memcache->set( - self::getApp()->get_hostname() . ":" . $key, + $cachekey, serialize($value), MEMCACHE_COMPRESSED, time() + $ttl ); } else { return $this->memcache->set( - self::getApp()->get_hostname() . ":" . $key, + $cachekey, serialize($value), MEMCACHE_COMPRESSED ); @@ -87,7 +89,8 @@ class MemcacheCacheDriver extends BaseObject implements IMemoryCacheDriver */ public function delete($key) { - return $this->memcache->delete($key); + $cachekey = $this->getCacheKey($key); + return $this->memcache->delete($cachekey); } /** @@ -103,6 +106,7 @@ class MemcacheCacheDriver extends BaseObject implements IMemoryCacheDriver */ public function add($key, $value, $ttl = Cache::FIVE_MINUTES) { - return $this->memcache->add(self::getApp()->get_hostname() . ":" . $key, $value, $ttl); + $cachekey = $this->getCacheKey($key); + return $this->memcache->add($cachekey, $value, $ttl); } } diff --git a/src/Core/Cache/MemcachedCacheDriver.php b/src/Core/Cache/MemcachedCacheDriver.php index dda36ba19c..52b6a08cf1 100644 --- a/src/Core/Cache/MemcachedCacheDriver.php +++ b/src/Core/Cache/MemcachedCacheDriver.php @@ -2,7 +2,6 @@ namespace Friendica\Core\Cache; -use Friendica\BaseObject; use Friendica\Core\Cache; /** @@ -10,7 +9,7 @@ use Friendica\Core\Cache; * * @author Hypolite Petovan */ -class MemcachedCacheDriver extends BaseObject implements IMemoryCacheDriver +class MemcachedCacheDriver extends AbstractCacheDriver { use TraitCompareSet; use TraitCompareDelete; @@ -38,9 +37,10 @@ class MemcachedCacheDriver extends BaseObject implements IMemoryCacheDriver public function get($key) { $return = null; + $cachekey = $this->getCacheKey($key); // We fetch with the hostname as key to avoid problems with other applications - $value = $this->memcached->get(self::getApp()->get_hostname() . ':' . $key); + $value = $this->memcached->get($cachekey); if ($this->memcached->getResultCode() === \Memcached::RES_SUCCESS) { $return = $value; @@ -51,16 +51,18 @@ class MemcachedCacheDriver extends BaseObject implements IMemoryCacheDriver public function set($key, $value, $ttl = Cache::FIVE_MINUTES) { + $cachekey = $this->getCacheKey($key); + // We store with the hostname as key to avoid problems with other applications if ($ttl > 0) { return $this->memcached->set( - self::getApp()->get_hostname() . ':' . $key, + $cachekey, $value, time() + $ttl ); } else { return $this->memcached->set( - self::getApp()->get_hostname() . ':' . $key, + $cachekey, $value ); } @@ -69,9 +71,8 @@ class MemcachedCacheDriver extends BaseObject implements IMemoryCacheDriver public function delete($key) { - $return = $this->memcached->delete(self::getApp()->get_hostname() . ':' . $key); - - return $return; + $cachekey = $this->getCacheKey($key); + return $this->memcached->delete($cachekey); } public function clear() @@ -89,6 +90,7 @@ class MemcachedCacheDriver extends BaseObject implements IMemoryCacheDriver */ public function add($key, $value, $ttl = Cache::FIVE_MINUTES) { - return $this->memcached->add(self::getApp()->get_hostname() . ":" . $key, $value, $ttl); + $cachekey = $this->getCacheKey($key); + return $this->memcached->add($cachekey, $value, $ttl); } } diff --git a/src/Core/Cache/RedisCacheDriver.php b/src/Core/Cache/RedisCacheDriver.php index 735418b2d2..8f85e67d78 100644 --- a/src/Core/Cache/RedisCacheDriver.php +++ b/src/Core/Cache/RedisCacheDriver.php @@ -2,7 +2,6 @@ namespace Friendica\Core\Cache; -use Friendica\BaseObject; use Friendica\Core\Cache; /** @@ -11,7 +10,7 @@ use Friendica\Core\Cache; * @author Hypolite Petovan * @author Roland Haeder */ -class RedisCacheDriver extends BaseObject implements IMemoryCacheDriver +class RedisCacheDriver extends AbstractCacheDriver { /** * @var \Redis @@ -34,9 +33,10 @@ class RedisCacheDriver extends BaseObject implements IMemoryCacheDriver public function get($key) { $return = null; + $cachekey = $this->getCacheKey($key); // We fetch with the hostname as key to avoid problems with other applications - $cached = $this->redis->get(self::getApp()->get_hostname() . ':' . $key); + $cached = $this->redis->get($cachekey); // @see http://php.net/manual/en/redis.get.php#84275 if (is_bool($cached) || is_double($cached) || is_long($cached)) { @@ -57,16 +57,18 @@ class RedisCacheDriver extends BaseObject implements IMemoryCacheDriver public function set($key, $value, $ttl = Cache::FIVE_MINUTES) { + $cachekey = $this->getCacheKey($key); + // We store with the hostname as key to avoid problems with other applications if ($ttl > 0) { return $this->redis->setex( - self::getApp()->get_hostname() . ":" . $key, + $cachekey, time() + $ttl, serialize($value) ); } else { return $this->redis->set( - self::getApp()->get_hostname() . ":" . $key, + $cachekey, serialize($value) ); } @@ -88,11 +90,13 @@ class RedisCacheDriver extends BaseObject implements IMemoryCacheDriver */ public function add($key, $value, $ttl = Cache::FIVE_MINUTES) { + $cachekey = $this->getCacheKey($key); + if (!is_int($value)) { $value = serialize($value); } - return $this->redis->setnx(self::getApp()->get_hostname() . ":" . $key, $value); + return $this->redis->setnx($cachekey, $value); } /** @@ -100,20 +104,22 @@ class RedisCacheDriver extends BaseObject implements IMemoryCacheDriver */ public function compareSet($key, $oldValue, $newValue, $ttl = Cache::FIVE_MINUTES) { + $cachekey = $this->getCacheKey($key); + if (!is_int($newValue)) { $newValue = serialize($newValue); } - $this->redis->watch(self::getApp()->get_hostname() . ":" . $key); + $this->redis->watch($cachekey); // If the old value isn't what we expected, somebody else changed the key meanwhile - if ($this->get($key) === $oldValue) { + if ($this->get($cachekey) === $oldValue) { if ($ttl > 0) { $result = $this->redis->multi() - ->setex(self::getApp()->get_hostname() . ":" . $ttl, $key, $newValue) + ->setex($cachekey, $ttl, $newValue) ->exec(); } else { $result = $this->redis->multi() - ->set(self::getApp()->get_hostname() . ":" . $key, $newValue) + ->set($cachekey, $newValue) ->exec(); } return $result !== false; @@ -126,11 +132,13 @@ class RedisCacheDriver extends BaseObject implements IMemoryCacheDriver */ public function compareDelete($key, $value) { - $this->redis->watch(self::getApp()->get_hostname() . ":" . $key); + $cachekey = $this->getCacheKey($key); + + $this->redis->watch($cachekey); // If the old value isn't what we expected, somebody else changed the key meanwhile if ($this->get($key) === $value) { $result = $this->redis->multi() - ->del(self::getApp()->get_hostname() . ":" . $key) + ->del($cachekey) ->exec(); return $result !== false; } diff --git a/src/Core/Lock/CacheLockDriver.php b/src/Core/Lock/CacheLockDriver.php index 2dd6f3fad9..ccbbb8a350 100644 --- a/src/Core/Lock/CacheLockDriver.php +++ b/src/Core/Lock/CacheLockDriver.php @@ -29,7 +29,7 @@ class CacheLockDriver extends AbstractLockDriver $got_lock = false; $start = time(); - $cachekey = self::getCacheKey($key); + $cachekey = self::getLockKey($key); do { $lock = $this->cache->get($cachekey); @@ -62,7 +62,7 @@ class CacheLockDriver extends AbstractLockDriver */ public function releaseLock($key) { - $cachekey = self::getCacheKey($key); + $cachekey = self::getLockKey($key); $this->cache->compareDelete($cachekey, getmypid()); $this->markRelease($key); @@ -73,7 +73,7 @@ class CacheLockDriver extends AbstractLockDriver */ public function isLocked($key) { - $cachekey = self::getCacheKey($key); + $cachekey = self::getLockKey($key); $lock = $this->cache->get($cachekey); return isset($lock) && ($lock !== false); } @@ -82,7 +82,7 @@ class CacheLockDriver extends AbstractLockDriver * @param string $key The original key * @return string The cache key used for the cache */ - private static function getCacheKey($key) { - return self::getApp()->get_hostname() . ";lock:" . $key; + private static function getLockKey($key) { + return "lock:" . $key; } } From 749b167fd9be7b02118a3311ed62e5cdbe2d931f Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Thu, 5 Jul 2018 21:54:20 +0200 Subject: [PATCH 50/65] AbstractCacheDriver now working for each CacheDriver --- src/Core/Cache/AbstractCacheDriver.php | 2 +- src/Core/Cache/ArrayCache.php | 2 +- src/Core/Cache/DatabaseCacheDriver.php | 2 +- src/Core/Cache/MemcacheCacheDriver.php | 2 +- src/Core/Cache/MemcachedCacheDriver.php | 2 +- src/Core/Cache/RedisCacheDriver.php | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Core/Cache/AbstractCacheDriver.php b/src/Core/Cache/AbstractCacheDriver.php index 6974dff1bd..ac33467b96 100644 --- a/src/Core/Cache/AbstractCacheDriver.php +++ b/src/Core/Cache/AbstractCacheDriver.php @@ -11,7 +11,7 @@ use Friendica\BaseObject; * * @package Friendica\Core\Cache */ -abstract class AbstractCacheDriver extends BaseObject implements IMemoryCacheDriver +abstract class AbstractCacheDriver extends BaseObject { /** * @param string $key The original key diff --git a/src/Core/Cache/ArrayCache.php b/src/Core/Cache/ArrayCache.php index 714021c723..ec9f3a2577 100644 --- a/src/Core/Cache/ArrayCache.php +++ b/src/Core/Cache/ArrayCache.php @@ -12,7 +12,7 @@ use Friendica\Core\Cache; * * @package Friendica\Core\Cache */ -class ArrayCache extends AbstractCacheDriver +class ArrayCache extends AbstractCacheDriver implements IMemoryCacheDriver { use TraitCompareDelete; diff --git a/src/Core/Cache/DatabaseCacheDriver.php b/src/Core/Cache/DatabaseCacheDriver.php index 0838a66c7a..5c71fb1962 100644 --- a/src/Core/Cache/DatabaseCacheDriver.php +++ b/src/Core/Cache/DatabaseCacheDriver.php @@ -12,7 +12,7 @@ use Friendica\Util\DateTimeFormat; * * @author Hypolite Petovan */ -class DatabaseCacheDriver implements ICacheDriver +class DatabaseCacheDriver extends AbstractCacheDriver implements ICacheDriver { public function get($key) { diff --git a/src/Core/Cache/MemcacheCacheDriver.php b/src/Core/Cache/MemcacheCacheDriver.php index 9c16d55312..af7e5ab0e2 100644 --- a/src/Core/Cache/MemcacheCacheDriver.php +++ b/src/Core/Cache/MemcacheCacheDriver.php @@ -9,7 +9,7 @@ use Friendica\Core\Cache; * * @author Hypolite Petovan */ -class MemcacheCacheDriver extends AbstractCacheDriver +class MemcacheCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver { use TraitCompareSet; use TraitCompareDelete; diff --git a/src/Core/Cache/MemcachedCacheDriver.php b/src/Core/Cache/MemcachedCacheDriver.php index 52b6a08cf1..819cf71c5c 100644 --- a/src/Core/Cache/MemcachedCacheDriver.php +++ b/src/Core/Cache/MemcachedCacheDriver.php @@ -9,7 +9,7 @@ use Friendica\Core\Cache; * * @author Hypolite Petovan */ -class MemcachedCacheDriver extends AbstractCacheDriver +class MemcachedCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver { use TraitCompareSet; use TraitCompareDelete; diff --git a/src/Core/Cache/RedisCacheDriver.php b/src/Core/Cache/RedisCacheDriver.php index 8f85e67d78..67df8e8fee 100644 --- a/src/Core/Cache/RedisCacheDriver.php +++ b/src/Core/Cache/RedisCacheDriver.php @@ -10,7 +10,7 @@ use Friendica\Core\Cache; * @author Hypolite Petovan * @author Roland Haeder */ -class RedisCacheDriver extends AbstractCacheDriver +class RedisCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver { /** * @var \Redis From 5a28ad7377b523d871d7dd44609f005232c3d566 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Thu, 5 Jul 2018 22:01:33 +0200 Subject: [PATCH 51/65] AbstractCacheDriver now working for each CacheDriver --- src/Core/Cache/AbstractCacheDriver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/Cache/AbstractCacheDriver.php b/src/Core/Cache/AbstractCacheDriver.php index ac33467b96..417accdce7 100644 --- a/src/Core/Cache/AbstractCacheDriver.php +++ b/src/Core/Cache/AbstractCacheDriver.php @@ -20,4 +20,4 @@ abstract class AbstractCacheDriver extends BaseObject protected function getCacheKey($key) { return self::getApp()->get_hostname() . ":" . $key; } -} \ No newline at end of file +} From 100c5e33ac45e9119239a3ca246aecfc3b6d02f8 Mon Sep 17 00:00:00 2001 From: Tobias Diekershoff Date: Fri, 6 Jul 2018 06:27:59 +0200 Subject: [PATCH 52/65] CS translation update THX Aditoo --- view/lang/cs/messages.po | 72 ++++++++++++++++++++-------------------- view/lang/cs/strings.php | 70 +++++++++++++++++++------------------- 2 files changed, 71 insertions(+), 71 deletions(-) diff --git a/view/lang/cs/messages.po b/view/lang/cs/messages.po index 7984a34e66..07aad54e20 100644 --- a/view/lang/cs/messages.po +++ b/view/lang/cs/messages.po @@ -13,7 +13,7 @@ msgstr "" "Project-Id-Version: friendica\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-06-30 17:33+0200\n" -"PO-Revision-Date: 2018-07-01 23:15+0000\n" +"PO-Revision-Date: 2018-07-06 02:27+0000\n" "Last-Translator: Aditoo\n" "Language-Team: Czech (http://www.transifex.com/Friendica/friendica/language/cs/)\n" "MIME-Version: 1.0\n" @@ -158,12 +158,12 @@ msgstr "fotka" #: src/Protocol/Diaspora.php:1945 #, php-format msgid "%1$s likes %2$s's %3$s" -msgstr "%1$s se líbí %3$s %2$s" +msgstr "Uživateli %1$s se líbí %3$s %2$s" #: include/conversation.php:170 src/Model/Item.php:2535 #, php-format msgid "%1$s doesn't like %2$s's %3$s" -msgstr "%1$s se nelíbí %3$s %2$s" +msgstr "Uživateli %1$s se nelíbí %3$s %2$s" #: include/conversation.php:172 #, php-format @@ -206,11 +206,11 @@ msgstr "uživatel %1$s označil %3$s %2$s jako oblíbené" #: include/conversation.php:504 mod/profiles.php:355 mod/photos.php:1464 msgid "Likes" -msgstr "Libí se mi" +msgstr "Libí se" #: include/conversation.php:504 mod/profiles.php:359 mod/photos.php:1464 msgid "Dislikes" -msgstr "Nelibí se mi" +msgstr "Nelibí se" #: include/conversation.php:505 include/conversation.php:1455 #: mod/photos.php:1465 @@ -320,12 +320,12 @@ msgstr "Připojit / Následovat" #: include/conversation.php:969 #, php-format msgid "%s likes this." -msgstr "%s se to líbí." +msgstr "Uživateli %s se tohle líbí." #: include/conversation.php:972 #, php-format msgid "%s doesn't like this." -msgstr "%s se to nelíbí." +msgstr "Uživateli %s se tohle nelíbí." #: include/conversation.php:975 #, php-format @@ -354,22 +354,22 @@ msgstr "a dalších %d lidí" #: include/conversation.php:1007 #, php-format msgid "%2$d people like this" -msgstr "%2$d lidem se to líbí" +msgstr "%2$d lidem se tohle líbí" #: include/conversation.php:1008 #, php-format msgid "%s like this." -msgstr "%s se tohle líbí." +msgstr "Uživatelům %s se tohle líbí." #: include/conversation.php:1011 #, php-format msgid "%2$d people don't like this" -msgstr "%2$d lidem se to nelíbí" +msgstr "%2$d lidem se tohle nelíbí" #: include/conversation.php:1012 #, php-format msgid "%s don't like this." -msgstr "%s se tohle nelíbí." +msgstr "Uživatelům %s se tohle nelíbí." #: include/conversation.php:1015 #, php-format @@ -596,12 +596,12 @@ msgstr "Děkujeme, " #: include/enotify.php:38 #, php-format msgid "%s Administrator" -msgstr "%s administrátor" +msgstr "Administrátor %s" #: include/enotify.php:40 #, php-format msgid "%1$s, %2$s Administrator" -msgstr "%1$s, %2$s administrátor" +msgstr "%1$s, administrátor %2$s" #: include/enotify.php:96 #, php-format @@ -740,12 +740,12 @@ msgstr "[Friendica:Oznámení] Obdrženo představení" #: include/enotify.php:262 #, php-format msgid "You've received an introduction from '%1$s' at %2$s" -msgstr "Obdržel/a jste představení od \"%1$s\" na %2$s" +msgstr "Obdržel/a jste představení od uživatele \"%1$s\" na %2$s" #: include/enotify.php:263 #, php-format msgid "You've received [url=%1$s]an introduction[/url] from %2$s." -msgstr "Obdržel/a jste [url=%1$s]představení[/url] od %2$s." +msgstr "Obdržel/a jste [url=%1$s]představení[/url] od uživatele %2$s." #: include/enotify.php:268 include/enotify.php:314 #, php-format @@ -782,13 +782,13 @@ msgstr "[Friendica:Oznámení] Obdržen návrh pro přátelství" #: include/enotify.php:305 #, php-format msgid "You've received a friend suggestion from '%1$s' at %2$s" -msgstr "Obdržel jste návrh pro přátelství od '%1$s' na %2$s" +msgstr "Obdržel/a jste návrh pro přátelství od uživatele \"%1$s\" na %2$s" #: include/enotify.php:306 #, php-format msgid "" "You've received [url=%1$s]a friend suggestion[/url] for %2$s from %3$s." -msgstr "Obdržel jste [url=%1$s]návrh pro přátelství[/url] s %2$s from %3$s." +msgstr "Obdržel/a jste [url=%1$s]návrh pro přátelství[/url] s uživatelem %2$s od uživatele %3$s." #: include/enotify.php:312 msgid "Name:" @@ -810,12 +810,12 @@ msgstr "[Friendica:Oznámení] Spojení akceptováno" #: include/enotify.php:326 include/enotify.php:341 #, php-format msgid "'%1$s' has accepted your connection request at %2$s" -msgstr "\"%1$s\" akceptoval váš požadavek na spojení na %2$s" +msgstr "\"%1$s\" akceptoval/a Váš požadavek na spojení na %2$s" #: include/enotify.php:327 include/enotify.php:342 #, php-format msgid "%2$s has accepted your [url=%1$s]connection request[/url]." -msgstr "%2$s akceptoval váš [url=%1$s]požadavek na spojení[/url]." +msgstr "%2$s akceptoval/a Váš [url=%1$s]požadavek na spojení[/url]." #: include/enotify.php:332 msgid "" @@ -860,12 +860,12 @@ msgstr "žádost o registraci" #: include/enotify.php:363 #, php-format msgid "You've received a registration request from '%1$s' at %2$s" -msgstr "Obdržel jste žádost o registraci od '%1$s' na %2$s" +msgstr "Obdržel/a jste žádost o registraci od uživatele \"%1$s\" na %2$s" #: include/enotify.php:364 #, php-format msgid "You've received a [url=%1$s]registration request[/url] from %2$s." -msgstr "Obdržel jste [url=%1$s]žádost o registraci[/url] od '%2$s'." +msgstr "Obdržel/a jste [url=%1$s]žádost o registraci[/url] od uživatele \"%2$s\"." #: include/enotify.php:369 #, php-format @@ -972,7 +972,7 @@ msgstr "šťouchnout" #: include/text.php:1043 msgid "poked" -msgstr "šťouchnul" +msgstr "šťouchnul/a" #: include/text.php:1044 msgid "ping" @@ -980,7 +980,7 @@ msgstr "cinknout" #: include/text.php:1044 msgid "pinged" -msgstr "cinknul" +msgstr "cinknul/a" #: include/text.php:1045 msgid "prod" @@ -988,7 +988,7 @@ msgstr "dloubnout" #: include/text.php:1045 msgid "prodded" -msgstr "dloubnul" +msgstr "dloubnul/a" #: include/text.php:1046 msgid "slap" @@ -996,15 +996,15 @@ msgstr "uhodit" #: include/text.php:1046 msgid "slapped" -msgstr "uhodil" +msgstr "uhodil/a" #: include/text.php:1047 msgid "finger" -msgstr "osahávat" +msgstr "osahat" #: include/text.php:1047 msgid "fingered" -msgstr "osahal" +msgstr "osahal/a" #: include/text.php:1048 msgid "rebuff" @@ -1012,7 +1012,7 @@ msgstr "odmítnout" #: include/text.php:1048 msgid "rebuffed" -msgstr "odmítnul" +msgstr "odmítnul/a" #: include/text.php:1062 mod/settings.php:935 src/Model/Event.php:379 msgid "Monday" @@ -1361,7 +1361,7 @@ msgid "" "On your Settings page - change your initial password. Also make a " "note of your Identity Address. This looks just like an email address - and " "will be useful in making friends on the free social web." -msgstr "Na Vaší stránce Nastavení si změňte Vaše první heslo.\nVěnujte také svou pozornost k adrese Identity. Vypadá jako emailová adresa a bude Vám užitečná pro navazování přátelství na svobodném sociálním webu." +msgstr "Na Vaší stránce Nastavení si změňte Vaše první heslo. Věnujte také svou pozornost k adrese Identity. Vypadá jako emailová adresa a bude Vám užitečná pro navazování přátelství na svobodném sociálním webu." #: mod/newmember.php:22 msgid "" @@ -2089,7 +2089,7 @@ msgstr "Odpovězte, prosím, následující:" #: mod/follow.php:150 mod/dfrn_request.php:647 #, php-format msgid "Does %s know you?" -msgstr "Zná Vás uživatel %s ?" +msgstr "Zná Vás %s ?" #: mod/follow.php:151 mod/dfrn_request.php:648 msgid "Add a personal note:" @@ -2607,7 +2607,7 @@ msgstr "Vaše databáze Friendica byla nainstalována." msgid "" "You may need to import the file \"database.sql\" manually using phpmyadmin " "or mysql." -msgstr "Pravděpodobně budete muset manuálně importovat soubor \"database.sql\" pomocí phpMyAdmin či MySQL." +msgstr "Nejspíše budete muset manuálně importovat soubor \"database.sql\" pomocí phpMyAdmin či MySQL." #: mod/install.php:109 mod/install.php:155 mod/install.php:267 msgid "Please see the file \"INSTALL.txt\"." @@ -2639,7 +2639,7 @@ msgstr "Pro instalaci Friendica potřeujeme znát připojení k Vaší databázi msgid "" "Please contact your hosting provider or site administrator if you have " "questions about these settings." -msgstr "Pokud máte otázky k následujícím nastavením, obraťte se na svého poskytovatele hostingu nebo administrátora serveru, " +msgstr "Pokud máte otázky k následujícím nastavením, obraťte se na svého poskytovatele hostingu nebo administrátora serveru." #: mod/install.php:180 msgid "" @@ -4150,7 +4150,7 @@ msgstr "Jste označen v příspěvku" #: mod/settings.php:1249 msgid "You are poked/prodded/etc. in a post" -msgstr "Byl jste šťouchnut(a)/dloubnut(a)/apod. v příspěvku" +msgstr "Byl/a jste šťouchnut(a)/dloubnut(a)/apod. v příspěvku" #: mod/settings.php:1251 msgid "Activate desktop notifications" @@ -4319,7 +4319,7 @@ msgstr "vyzkoušet webfinger" #: mod/admin.php:223 src/Content/Nav.php:218 msgid "Admin" -msgstr "Administrace" +msgstr "Administrátor" #: mod/admin.php:224 msgid "Addon Features" @@ -5678,7 +5678,7 @@ msgid "" "\n" "\t\t\tDear %1$s,\n" "\t\t\t\tthe administrator of %2$s has set up an account for you." -msgstr "\n\t\t\tVážený/á%1$s,\n\t\t\t\tadministrátor %2$s pro Vás vytvořil/a uživatelský účet." +msgstr "\n\t\t\tVážený/á%1$s,\n\t\t\t\tadministrátor %2$s pro Vás vytvořil uživatelský účet." #: mod/admin.php:1597 #, php-format @@ -5809,7 +5809,7 @@ msgstr "Odmítnout" #: mod/admin.php:1835 msgid "Site admin" -msgstr "Site administrátor" +msgstr "Administrátor webu" #: mod/admin.php:1836 msgid "Account expired" diff --git a/view/lang/cs/strings.php b/view/lang/cs/strings.php index fc89a8a571..9bdcd2ad27 100644 --- a/view/lang/cs/strings.php +++ b/view/lang/cs/strings.php @@ -34,8 +34,8 @@ $a->strings["Profile Photos"] = "Profilové fotky"; $a->strings["event"] = "událost"; $a->strings["status"] = "stav"; $a->strings["photo"] = "fotka"; -$a->strings["%1\$s likes %2\$s's %3\$s"] = "%1\$s se líbí %3\$s %2\$s"; -$a->strings["%1\$s doesn't like %2\$s's %3\$s"] = "%1\$s se nelíbí %3\$s %2\$s"; +$a->strings["%1\$s likes %2\$s's %3\$s"] = "Uživateli %1\$s se líbí %3\$s %2\$s"; +$a->strings["%1\$s doesn't like %2\$s's %3\$s"] = "Uživateli %1\$s se nelíbí %3\$s %2\$s"; $a->strings["%1\$s attends %2\$s's %3\$s"] = "%1\$s se účastní %3\$s %2\$s"; $a->strings["%1\$s doesn't attend %2\$s's %3\$s"] = "%1\$s se neúčastní %3\$s %2\$s"; $a->strings["%1\$s attends maybe %2\$s's %3\$s"] = "%1\$s se možná účastní %3\$s %2\$s"; @@ -44,8 +44,8 @@ $a->strings["%1\$s poked %2\$s"] = "%1\$s šťouchnul %2\$s"; $a->strings["%1\$s tagged %2\$s's %3\$s with %4\$s"] = "%1\$s označil %3\$s %2\$s s %4\$s"; $a->strings["post/item"] = "příspěvek/položka"; $a->strings["%1\$s marked %2\$s's %3\$s as favorite"] = "uživatel %1\$s označil %3\$s %2\$s jako oblíbené"; -$a->strings["Likes"] = "Libí se mi"; -$a->strings["Dislikes"] = "Nelibí se mi"; +$a->strings["Likes"] = "Libí se"; +$a->strings["Dislikes"] = "Nelibí se"; $a->strings["Attending"] = [ 0 => "Účastní se", 1 => "Účastní se", @@ -73,17 +73,17 @@ $a->strings["View Contact"] = "Zobrazit kontakt"; $a->strings["Send PM"] = "Poslat soukromou zprávu"; $a->strings["Poke"] = "Šťouchnout"; $a->strings["Connect/Follow"] = "Připojit / Následovat"; -$a->strings["%s likes this."] = "%s se to líbí."; -$a->strings["%s doesn't like this."] = "%s se to nelíbí."; +$a->strings["%s likes this."] = "Uživateli %s se tohle líbí."; +$a->strings["%s doesn't like this."] = "Uživateli %s se tohle nelíbí."; $a->strings["%s attends."] = "%s se účastní."; $a->strings["%s doesn't attend."] = "%s se neúčastní."; $a->strings["%s attends maybe."] = "%s se možná účastní."; $a->strings["and"] = "a"; $a->strings["and %d other people"] = "a dalších %d lidí"; -$a->strings["%2\$d people like this"] = "%2\$d lidem se to líbí"; -$a->strings["%s like this."] = "%s se tohle líbí."; -$a->strings["%2\$d people don't like this"] = "%2\$d lidem se to nelíbí"; -$a->strings["%s don't like this."] = "%s se tohle nelíbí."; +$a->strings["%2\$d people like this"] = "%2\$d lidem se tohle líbí"; +$a->strings["%s like this."] = "Uživatelům %s se tohle líbí."; +$a->strings["%2\$d people don't like this"] = "%2\$d lidem se tohle nelíbí"; +$a->strings["%s don't like this."] = "Uživatelům %s se tohle nelíbí."; $a->strings["%2\$d people attend"] = "%2\$d lidí se účastní"; $a->strings["%s attend."] = "%s se účastní."; $a->strings["%2\$d people don't attend"] = "%2\$d lidí se neúčastní"; @@ -152,8 +152,8 @@ $a->strings["Undecided"] = [ ]; $a->strings["Friendica Notification"] = "Oznámení Friendica"; $a->strings["Thank You,"] = "Děkujeme, "; -$a->strings["%s Administrator"] = "%s administrátor"; -$a->strings["%1\$s, %2\$s Administrator"] = "%1\$s, %2\$s administrátor"; +$a->strings["%s Administrator"] = "Administrátor %s"; +$a->strings["%1\$s, %2\$s Administrator"] = "%1\$s, administrátor %2\$s"; $a->strings["[Friendica:Notify] New mail received at %s"] = "[Friendica:Oznámení] Obdržena nová zpráva na %s"; $a->strings["%1\$s sent you a new private message at %2\$s."] = "%1\$s Vám poslal/a novou soukromou zprávu na %2\$s."; $a->strings["a private message"] = "soukromou zprávu"; @@ -181,8 +181,8 @@ $a->strings["[Friendica:Notify] %s tagged your post"] = "[Friendica:Oznámení] $a->strings["%1\$s tagged your post at %2\$s"] = "%1\$s označil/a Váš příspěvek na%2\$s"; $a->strings["%1\$s tagged [url=%2\$s]your post[/url]"] = "%1\$s označil/a [url=%2\$s]Váš příspěvek[/url]"; $a->strings["[Friendica:Notify] Introduction received"] = "[Friendica:Oznámení] Obdrženo představení"; -$a->strings["You've received an introduction from '%1\$s' at %2\$s"] = "Obdržel/a jste představení od \"%1\$s\" na %2\$s"; -$a->strings["You've received [url=%1\$s]an introduction[/url] from %2\$s."] = "Obdržel/a jste [url=%1\$s]představení[/url] od %2\$s."; +$a->strings["You've received an introduction from '%1\$s' at %2\$s"] = "Obdržel/a jste představení od uživatele \"%1\$s\" na %2\$s"; +$a->strings["You've received [url=%1\$s]an introduction[/url] from %2\$s."] = "Obdržel/a jste [url=%1\$s]představení[/url] od uživatele %2\$s."; $a->strings["You may visit their profile at %s"] = "Můžete navštívit jejich profil na %s"; $a->strings["Please visit %s to approve or reject the introduction."] = "Prosím navštivte %s pro schválení či zamítnutí představení."; $a->strings["[Friendica:Notify] A new person is sharing with you"] = "[Friendica:Oznámení] Nový člověk s vámi sdílí"; @@ -190,14 +190,14 @@ $a->strings["%1\$s is sharing with you at %2\$s"] = "Uživatel %1\$s s vámi sd $a->strings["[Friendica:Notify] You have a new follower"] = "[Friendica:Oznámení] Máte nového sledovatele"; $a->strings["You have a new follower at %2\$s : %1\$s"] = "Máte nového sledovatele na %2\$s : %1\$s"; $a->strings["[Friendica:Notify] Friend suggestion received"] = "[Friendica:Oznámení] Obdržen návrh pro přátelství"; -$a->strings["You've received a friend suggestion from '%1\$s' at %2\$s"] = "Obdržel jste návrh pro přátelství od '%1\$s' na %2\$s"; -$a->strings["You've received [url=%1\$s]a friend suggestion[/url] for %2\$s from %3\$s."] = "Obdržel jste [url=%1\$s]návrh pro přátelství[/url] s %2\$s from %3\$s."; +$a->strings["You've received a friend suggestion from '%1\$s' at %2\$s"] = "Obdržel/a jste návrh pro přátelství od uživatele \"%1\$s\" na %2\$s"; +$a->strings["You've received [url=%1\$s]a friend suggestion[/url] for %2\$s from %3\$s."] = "Obdržel/a jste [url=%1\$s]návrh pro přátelství[/url] s uživatelem %2\$s od uživatele %3\$s."; $a->strings["Name:"] = "Jméno:"; $a->strings["Photo:"] = "Foto:"; $a->strings["Please visit %s to approve or reject the suggestion."] = "Prosím navštivte %s pro schválení či zamítnutí doporučení."; $a->strings["[Friendica:Notify] Connection accepted"] = "[Friendica:Oznámení] Spojení akceptováno"; -$a->strings["'%1\$s' has accepted your connection request at %2\$s"] = "\"%1\$s\" akceptoval váš požadavek na spojení na %2\$s"; -$a->strings["%2\$s has accepted your [url=%1\$s]connection request[/url]."] = "%2\$s akceptoval váš [url=%1\$s]požadavek na spojení[/url]."; +$a->strings["'%1\$s' has accepted your connection request at %2\$s"] = "\"%1\$s\" akceptoval/a Váš požadavek na spojení na %2\$s"; +$a->strings["%2\$s has accepted your [url=%1\$s]connection request[/url]."] = "%2\$s akceptoval/a Váš [url=%1\$s]požadavek na spojení[/url]."; $a->strings["You are now mutual friends and may exchange status updates, photos, and email without restriction."] = "Jste nyní vzájemní přátelé a můžete si vyměňovat aktualizace stavu, fotky a e-maily bez omezení."; $a->strings["Please visit %s if you wish to make any changes to this relationship."] = "Pokud chcete provést změny s tímto vztahem, prosím navštivte %s."; $a->strings["'%1\$s' has chosen to accept you a fan, which restricts some forms of communication - such as private messaging and some profile interactions. If this is a celebrity or community page, these settings were applied automatically."] = "\"%1\$s\" se rozhodl/a Vás přijmout jako fanouška, což omezuje některé formy komunikace - například soukoromé zprávy a některé interakce s profily. Pokud je toto stránka celebrity či komunity, byla tato nastavení aplikována automaticky."; @@ -205,8 +205,8 @@ $a->strings["'%1\$s' may choose to extend this into a two-way or more permissive $a->strings["Please visit %s if you wish to make any changes to this relationship."] = "Prosím navštivte %s pokud chcete změnit tento vztah."; $a->strings["[Friendica System Notify]"] = "[Oznámení systému Friendica]"; $a->strings["registration request"] = "žádost o registraci"; -$a->strings["You've received a registration request from '%1\$s' at %2\$s"] = "Obdržel jste žádost o registraci od '%1\$s' na %2\$s"; -$a->strings["You've received a [url=%1\$s]registration request[/url] from %2\$s."] = "Obdržel jste [url=%1\$s]žádost o registraci[/url] od '%2\$s'."; +$a->strings["You've received a registration request from '%1\$s' at %2\$s"] = "Obdržel/a jste žádost o registraci od uživatele \"%1\$s\" na %2\$s"; +$a->strings["You've received a [url=%1\$s]registration request[/url] from %2\$s."] = "Obdržel/a jste [url=%1\$s]žádost o registraci[/url] od uživatele \"%2\$s\"."; $a->strings["Full Name:\t%s\nSite Location:\t%s\nLogin Name:\t%s (%s)"] = "Celé jméno:\t\t%s\nAdresa stránky:\t\t%s\nPřihlašovací jméno:\t%s (%s)"; $a->strings["Please visit %s to approve or reject the request."] = "Prosím navštivte %s k odsouhlasení nebo k zamítnutí požadavku."; $a->strings["newer"] = "novější"; @@ -234,17 +234,17 @@ $a->strings["Tags"] = "Štítky:"; $a->strings["Contacts"] = "Kontakty"; $a->strings["Forums"] = "Fóra"; $a->strings["poke"] = "šťouchnout"; -$a->strings["poked"] = "šťouchnul"; +$a->strings["poked"] = "šťouchnul/a"; $a->strings["ping"] = "cinknout"; -$a->strings["pinged"] = "cinknul"; +$a->strings["pinged"] = "cinknul/a"; $a->strings["prod"] = "dloubnout"; -$a->strings["prodded"] = "dloubnul"; +$a->strings["prodded"] = "dloubnul/a"; $a->strings["slap"] = "uhodit"; -$a->strings["slapped"] = "uhodil"; -$a->strings["finger"] = "osahávat"; -$a->strings["fingered"] = "osahal"; +$a->strings["slapped"] = "uhodil/a"; +$a->strings["finger"] = "osahat"; +$a->strings["fingered"] = "osahal/a"; $a->strings["rebuff"] = "odmítnout"; -$a->strings["rebuffed"] = "odmítnul"; +$a->strings["rebuffed"] = "odmítnul/a"; $a->strings["Monday"] = "Pondělí"; $a->strings["Tuesday"] = "Úterý"; $a->strings["Wednesday"] = "Středa"; @@ -328,7 +328,7 @@ $a->strings["Friendica Walk-Through"] = "Prohlídka Friendica "; $a->strings["On your Quick Start page - find a brief introduction to your profile and network tabs, make some new connections, and find some groups to join."] = "Na Vaší stránce Rychlý Start najděte stručné představení k Vašemu profilu a síťovým záložkám, spojte ses novými kontakty a jděte skupiny, ke kterým se můžete připojit."; $a->strings["Settings"] = "Nastavení"; $a->strings["Go to Your Settings"] = "Navštivte své nastavení"; -$a->strings["On your Settings page - change your initial password. Also make a note of your Identity Address. This looks just like an email address - and will be useful in making friends on the free social web."] = "Na Vaší stránce Nastavení si změňte Vaše první heslo.\nVěnujte také svou pozornost k adrese Identity. Vypadá jako emailová adresa a bude Vám užitečná pro navazování přátelství na svobodném sociálním webu."; +$a->strings["On your Settings page - change your initial password. Also make a note of your Identity Address. This looks just like an email address - and will be useful in making friends on the free social web."] = "Na Vaší stránce Nastavení si změňte Vaše první heslo. Věnujte také svou pozornost k adrese Identity. Vypadá jako emailová adresa a bude Vám užitečná pro navazování přátelství na svobodném sociálním webu."; $a->strings["Review the other settings, particularly the privacy settings. An unpublished directory listing is like having an unlisted phone number. In general, you should probably publish your listing - unless all of your friends and potential friends know exactly how to find you."] = "Prohlédněte si další nastavení, a to zejména nastavení soukromí. Nezveřejnění svého účtu v adresáři je jako mít nezveřejněné telefonní číslo. Obecně platí, že je lepší mít svůj účet zveřejněný, leda by všichni vaši přátelé a potenciální přátelé věděli, jak vás přesně najít."; $a->strings["Profile"] = "Profil"; $a->strings["Upload Profile Photo"] = "Nahrát profilovou fotografii"; @@ -484,7 +484,7 @@ $a->strings["Diaspora support isn't enabled. Contact can't be added."] = "Podpor $a->strings["OStatus support is disabled. Contact can't be added."] = "Podpora pro OStatus je vypnnuta. Kontakt nemůže být přidán."; $a->strings["The network type couldn't be detected. Contact can't be added."] = "Typ sítě nemohl být detekován. Kontakt nemůže být přidán."; $a->strings["Please answer the following:"] = "Odpovězte, prosím, následující:"; -$a->strings["Does %s know you?"] = "Zná Vás uživatel %s ?"; +$a->strings["Does %s know you?"] = "Zná Vás %s ?"; $a->strings["Add a personal note:"] = "Přidat osobní poznámku:"; $a->strings["Your Identity Address:"] = "Verze PHP pro příkazový řádek na Vašem systému nemá povolen \"register_argc_argv\"."; $a->strings["Profile URL"] = "URL profilu"; @@ -594,14 +594,14 @@ $a->strings["Friendica Communications Server - Setup"] = "Friendica Komunikačn $a->strings["Could not connect to database."] = "Nelze se připojit k databázi."; $a->strings["Could not create table."] = "Nelze vytvořit tabulku."; $a->strings["Your Friendica site database has been installed."] = "Vaše databáze Friendica byla nainstalována."; -$a->strings["You may need to import the file \"database.sql\" manually using phpmyadmin or mysql."] = "Pravděpodobně budete muset manuálně importovat soubor \"database.sql\" pomocí phpMyAdmin či MySQL."; +$a->strings["You may need to import the file \"database.sql\" manually using phpmyadmin or mysql."] = "Nejspíše budete muset manuálně importovat soubor \"database.sql\" pomocí phpMyAdmin či MySQL."; $a->strings["Please see the file \"INSTALL.txt\"."] = "Přečtěte si prosím informace v souboru \"INSTALL.txt\"."; $a->strings["Database already in use."] = "Databáze se již používá."; $a->strings["System check"] = "Testování systému"; $a->strings["Check again"] = "Otestovat znovu"; $a->strings["Database connection"] = "Databázové spojení"; $a->strings["In order to install Friendica we need to know how to connect to your database."] = "Pro instalaci Friendica potřeujeme znát připojení k Vaší databázi."; -$a->strings["Please contact your hosting provider or site administrator if you have questions about these settings."] = "Pokud máte otázky k následujícím nastavením, obraťte se na svého poskytovatele hostingu nebo administrátora serveru, "; +$a->strings["Please contact your hosting provider or site administrator if you have questions about these settings."] = "Pokud máte otázky k následujícím nastavením, obraťte se na svého poskytovatele hostingu nebo administrátora serveru."; $a->strings["The database you specify below should already exist. If it does not, please create it before continuing."] = "Databáze, kterou uvedete níže, by již měla existovat. Pokud to tak není, prosíme, vytvořte ji před pokračováním."; $a->strings["Database Server Name"] = "Jméno databázového serveru"; $a->strings["Database Login Name"] = "Přihlašovací jméno k databázi"; @@ -954,7 +954,7 @@ $a->strings["Someone writes a followup comment"] = "někdo Vám napíše násled $a->strings["You receive a private message"] = "obdržíte soukromou zprávu"; $a->strings["You receive a friend suggestion"] = "Obdržel jste návrh přátelství"; $a->strings["You are tagged in a post"] = "Jste označen v příspěvku"; -$a->strings["You are poked/prodded/etc. in a post"] = "Byl jste šťouchnut(a)/dloubnut(a)/apod. v příspěvku"; +$a->strings["You are poked/prodded/etc. in a post"] = "Byl/a jste šťouchnut(a)/dloubnut(a)/apod. v příspěvku"; $a->strings["Activate desktop notifications"] = "Aktivovat upozornění na desktopu"; $a->strings["Show desktop popup on new notifications"] = "Zobrazit dektopové zprávy nových upozornění."; $a->strings["Text-only notification emails"] = "Pouze textové notifikační e-maily"; @@ -995,7 +995,7 @@ $a->strings["Diagnostics"] = "Diagnostica"; $a->strings["PHP Info"] = "Info o PHP"; $a->strings["probe address"] = "vyzkoušet adresu"; $a->strings["check webfinger"] = "vyzkoušet webfinger"; -$a->strings["Admin"] = "Administrace"; +$a->strings["Admin"] = "Administrátor"; $a->strings["Addon Features"] = "Vlastnosti doplňků"; $a->strings["User registrations waiting for confirmation"] = "Registrace uživatele čeká na potvrzení"; $a->strings["Administration"] = "Administrace"; @@ -1290,7 +1290,7 @@ $a->strings["Failed Updates"] = "Neúspěšné aktualizace"; $a->strings["This does not include updates prior to 1139, which did not return a status."] = "To nezahrnuje aktualizace do verze 1139, které nevracejí žádný status."; $a->strings["Mark success (if update was manually applied)"] = "Označit za úspěšné (pokud byla aktualizace aplikována manuálně)"; $a->strings["Attempt to execute this update step automatically"] = "Pokusit se provést tuto aktualizaci automaticky."; -$a->strings["\n\t\t\tDear %1\$s,\n\t\t\t\tthe administrator of %2\$s has set up an account for you."] = "\n\t\t\tVážený/á%1\$s,\n\t\t\t\tadministrátor %2\$s pro Vás vytvořil/a uživatelský účet."; +$a->strings["\n\t\t\tDear %1\$s,\n\t\t\t\tthe administrator of %2\$s has set up an account for you."] = "\n\t\t\tVážený/á%1\$s,\n\t\t\t\tadministrátor %2\$s pro Vás vytvořil uživatelský účet."; $a->strings["\n\t\t\tThe login details are as follows:\n\n\t\t\tSite Location:\t%1\$s\n\t\t\tLogin Name:\t\t%2\$s\n\t\t\tPassword:\t\t%3\$s\n\n\t\t\tYou may change your password from your account \"Settings\" page after logging\n\t\t\tin.\n\n\t\t\tPlease take a few moments to review the other account settings on that page.\n\n\t\t\tYou may also wish to add some basic information to your default profile\n\t\t\t(on the \"Profiles\" page) so that other people can easily find you.\n\n\t\t\tWe recommend setting your full name, adding a profile photo,\n\t\t\tadding some profile \"keywords\" (very useful in making new friends) - and\n\t\t\tperhaps what country you live in; if you do not wish to be more specific\n\t\t\tthan that.\n\n\t\t\tWe fully respect your right to privacy, and none of these items are necessary.\n\t\t\tIf you are new and do not know anybody here, they may help\n\t\t\tyou to make some new and interesting friends.\n\n\t\t\tIf you ever want to delete your account, you can do so at %1\$s/removeme\n\n\t\t\tThank you and welcome to %4\$s."] = "\n\t\t\tZde jsou vaše přihlašovací detaily:\n\n\t\t\tAdresa stránky:\t\t%1\$s\n\t\t\tPřihlašovací jméno:\t%2\$s\n\t\t\tHeslo:\t\t\t%3\$s\n\n\t\t\tSvé heslo si po přihlášení můžete změnit na stránce \"Nastavení\" vašeho\n\t\t\túčtu.\n\n\t\t\tProsím, prohlédněte si na chvilku ostatní nastavení účtu na té stránce.\n\n\t\t\tMožná byste si také přáli přidat pár základních informací na svůj výchozí\n\t\t\tprofil (na stránce \"Profily\") aby vás další lidé mohli snadno najít.\n\t\t\tDoporučujeme nastavit si vaše celé jméno, přidat profilovou fotku,\n\t\t\tpřidat pár \"klíčových slov\" k profilu (velmi užitečné při získávání nových\n\t\t\tpřátel) - a možná v jaké zemi žijete; pokud nechcete být konkrétnější.\n\n\t\t\tZcela respektujeme vaše právo na soukromí a žádnou z těchto položek\n\t\t\tnení potřeba vyplňovat. Pokud jste zde nový/á a nikoho zde neznáte, mohou vám\n\t\t\tpomoci si získat nové a zajímavé přátele.\n\t\t\tPokud byste si někdy přál/a smazat účet, může tak učinit na stránce\n\t\t\t%1\$s/removeme.\n\n\t\t\tDěkujeme vám a vítáme vás na %4\$s."; $a->strings["Registration details for %s"] = "Registrační údaje pro %s"; $a->strings["%s user blocked/unblocked"] = [ @@ -1322,7 +1322,7 @@ $a->strings["No registrations."] = "Žádné registrace."; $a->strings["Note from the user"] = "Poznámka od uživatele"; $a->strings["Approve"] = "Schválit"; $a->strings["Deny"] = "Odmítnout"; -$a->strings["Site admin"] = "Site administrátor"; +$a->strings["Site admin"] = "Administrátor webu"; $a->strings["Account expired"] = "Účtu vypršela platnost"; $a->strings["New User"] = "Nový uživatel"; $a->strings["Deleted since"] = "Smazán od"; From 72638acac3dd6c25cdf707e316e735f4d8ceeec1 Mon Sep 17 00:00:00 2001 From: Tobias Diekershoff Date: Fri, 6 Jul 2018 15:32:56 +0200 Subject: [PATCH 53/65] admins can forbid some nicknames from being registered --- mod/admin.php | 5 +++++ src/Model/User.php | 29 +++++++++++++++++++++++++++++ view/templates/admin/site.tpl | 1 + 3 files changed, 35 insertions(+) diff --git a/mod/admin.php b/mod/admin.php index b43baa4433..f12ec5e3b2 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -975,6 +975,7 @@ function admin_page_site_post(App $a) $allowed_sites = ((x($_POST,'allowed_sites')) ? notags(trim($_POST['allowed_sites'])) : ''); $allowed_email = ((x($_POST,'allowed_email')) ? notags(trim($_POST['allowed_email'])) : ''); + $forbidden_nicknames = ((x($_POST,'forbidden_nicknames')) ? strtolower(notags(trim($_POST['forbidden_nicknames']))) : ''); $no_oembed_rich_content = x($_POST,'no_oembed_rich_content'); $allowed_oembed = ((x($_POST,'allowed_oembed')) ? notags(trim($_POST['allowed_oembed'])) : ''); $block_public = ((x($_POST,'block_public')) ? True : False); @@ -1143,6 +1144,7 @@ function admin_page_site_post(App $a) Config::set('config', 'register_text', $register_text); Config::set('system', 'allowed_sites', $allowed_sites); Config::set('system', 'allowed_email', $allowed_email); + Config::set('system', 'forbidden_nicknames', $forbidden_nicknames); Config::set('system', 'no_oembed_rich_content', $no_oembed_rich_content); Config::set('system', 'allowed_oembed', $allowed_oembed); Config::set('system', 'block_public', $block_public); @@ -1349,6 +1351,8 @@ function admin_page_site(App $a) if ($optimize_max_tablesize <= 0) { $optimize_max_tablesize = -1; } + // Default list of forbidden names, classic role names from RFC 2142 + $default_forbidden_nicknames = 'info, marketing, sales, support, abuse, noc, security, postmaster, hostmaster, usenet, news, webmaster, www, uucp, ftp, root, sysop'; $t = get_markup_template('admin/site.tpl'); return replace_macros($t, [ @@ -1388,6 +1392,7 @@ function admin_page_site(App $a) '$register_policy' => ['register_policy', L10n::t("Register policy"), $a->config['register_policy'], "", $register_choices], '$daily_registrations' => ['max_daily_registrations', L10n::t("Maximum Daily Registrations"), Config::get('system', 'max_daily_registrations'), L10n::t("If registration is permitted above, this sets the maximum number of new user registrations to accept per day. If register is set to closed, this setting has no effect.")], '$register_text' => ['register_text', L10n::t("Register text"), $a->config['register_text'], L10n::t("Will be displayed prominently on the registration page. You can use BBCode here.")], + '$forbidden_nicknames' => ['forbidden_nicknames', L10n::t('Forbidden Nicknames'), Config::get('system', 'forbidden_nicknames', $default_forbidden_nicknames), L10n::t('Comma separated list of nicknames that are forbidden from registration. Preset is a list of role names according RFC 2142.')], '$abandon_days' => ['abandon_days', L10n::t('Accounts abandoned after x days'), Config::get('system','account_abandon_days'), L10n::t('Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit.')], '$allowed_sites' => ['allowed_sites', L10n::t("Allowed friend domains"), Config::get('system','allowed_sites'), L10n::t("Comma separated list of domains which are allowed to establish friendships with this site. Wildcards are accepted. Empty to allow any domains")], '$allowed_email' => ['allowed_email', L10n::t("Allowed email domains"), Config::get('system','allowed_email'), L10n::t("Comma separated list of domains which are allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains")], diff --git a/src/Model/User.php b/src/Model/User.php index 6754f22070..f1fa32f48d 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -304,6 +304,32 @@ class User return dba::update('user', $fields, ['uid' => $uid]); } + /** + * @brief Checks if a nickname is in the list of the forbidden nicknames + * + * Check if a nickname is forbidden from registration on the node by the + * admin. Forbidden nicknames (e.g. role namess) can be configured in the + * admin panel. + * + * @param string $nickname The nickname that should be checked + * @return boolean True is the nickname is blocked on the node + */ + public static function isNicknameBlocked($nickname) + { + $forbidden_nicknames = Config::get('system', 'forbidden_nicknames', ''); + // if the config variable is empty return false + if (!x($forbidden_nicknames)) { + return false; + } + // check if the nickname is in the list of blocked nicknames + $forbidden = explode(',', $forbidden_nicknames); + if (in_array(strtolower($nickname), $forbidden)) { + return true; + } + // else return false + return false; + } + /** * @brief Catch-all user creation function * @@ -417,6 +443,9 @@ class User if (!valid_email($email) || !Network::isEmailDomainValid($email)) { throw new Exception(L10n::t('Not a valid email address.')); } + if (self::isNicknameBlocked($nickname)) { + throw new Exception(L10n::t('The nickname was blocked from registration by the nodes admin.')); + } if (Config::get('system', 'block_extended_register', false) && dba::exists('user', ['email' => $email])) { throw new Exception(L10n::t('Cannot use that email.')); diff --git a/view/templates/admin/site.tpl b/view/templates/admin/site.tpl index 0b46aa9919..31b3b68ca2 100644 --- a/view/templates/admin/site.tpl +++ b/view/templates/admin/site.tpl @@ -78,6 +78,7 @@

{{$corporate}}

{{include file="field_input.tpl" field=$allowed_sites}} {{include file="field_input.tpl" field=$allowed_email}} + {{include file="field_input.tpl" field=$forbidden_nicknames}} {{include file="field_checkbox.tpl" field=$no_oembed_rich_content}} {{include file="field_input.tpl" field=$allowed_oembed}} {{include file="field_checkbox.tpl" field=$block_public}} From a49e09430886057b3c00fcdb3ac0ec58cc97f6eb Mon Sep 17 00:00:00 2001 From: Tobias Diekershoff Date: Fri, 6 Jul 2018 15:49:27 +0200 Subject: [PATCH 54/65] added forgotten trim --- src/Model/User.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Model/User.php b/src/Model/User.php index f1fa32f48d..dc5702b605 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -323,6 +323,7 @@ class User } // check if the nickname is in the list of blocked nicknames $forbidden = explode(',', $forbidden_nicknames); + $forbidden = array_map('trim', $forbidden); if (in_array(strtolower($nickname), $forbidden)) { return true; } From ba7505f12f143ab337791398158a0f08f1458322 Mon Sep 17 00:00:00 2001 From: Tobias Diekershoff Date: Sat, 7 Jul 2018 11:22:18 +0200 Subject: [PATCH 55/65] CS translation update THX Aditoo --- view/lang/cs/messages.po | 38 +++++++++++++++++++------------------- view/lang/cs/strings.php | 36 ++++++++++++++++++------------------ 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/view/lang/cs/messages.po b/view/lang/cs/messages.po index 07aad54e20..b482b6ba95 100644 --- a/view/lang/cs/messages.po +++ b/view/lang/cs/messages.po @@ -13,7 +13,7 @@ msgstr "" "Project-Id-Version: friendica\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-06-30 17:33+0200\n" -"PO-Revision-Date: 2018-07-06 02:27+0000\n" +"PO-Revision-Date: 2018-07-06 22:09+0000\n" "Last-Translator: Aditoo\n" "Language-Team: Czech (http://www.transifex.com/Friendica/friendica/language/cs/)\n" "MIME-Version: 1.0\n" @@ -91,7 +91,7 @@ msgstr "Vítejte " #: include/security.php:82 msgid "Please upload a profile photo." -msgstr "Prosím nahrejte profilovou fotografii" +msgstr "Prosím nahrajte profilovou fotografii" #: include/security.php:84 msgid "Welcome back " @@ -183,7 +183,7 @@ msgstr "%1$s se možná účastní %3$s %2$s" #: include/conversation.php:211 #, php-format msgid "%1$s is now friends with %2$s" -msgstr "%1$s je nyní přítel s %2$s" +msgstr "%1$s je nyní přítel s uživatelem %2$s" #: include/conversation.php:252 #, php-format @@ -193,7 +193,7 @@ msgstr "%1$s šťouchnul %2$s" #: include/conversation.php:300 mod/tagger.php:108 #, php-format msgid "%1$s tagged %2$s's %3$s with %4$s" -msgstr "%1$s označil %3$s %2$s s %4$s" +msgstr "%1$s označil/a %3$s uživatele %2$s jako %4$s" #: include/conversation.php:322 msgid "post/item" @@ -202,7 +202,7 @@ msgstr "příspěvek/položka" #: include/conversation.php:323 #, php-format msgid "%1$s marked %2$s's %3$s as favorite" -msgstr "uživatel %1$s označil %3$s %2$s jako oblíbené" +msgstr "%1$s označil/a %3$s uživatele %2$s jako oblíbené" #: include/conversation.php:504 mod/profiles.php:355 mod/photos.php:1464 msgid "Likes" @@ -530,11 +530,11 @@ msgstr "Náhled" #: include/conversation.php:1153 msgid "Post to Groups" -msgstr "Zveřejnit na Groups" +msgstr "Zveřejnit ve skupinách" #: include/conversation.php:1154 msgid "Post to Contacts" -msgstr "Zveřejnit na Groups" +msgstr "Zveřejnit v kontaktech" #: include/conversation.php:1155 msgid "Private post" @@ -939,7 +939,7 @@ msgstr "Sledovat" #: include/text.php:985 mod/search.php:156 src/Content/Nav.php:142 msgid "Search" -msgstr "Vyhledávání" +msgstr "Hledat" #: include/text.php:988 src/Content/Nav.php:58 msgid "@name, !forum, #tags, content" @@ -3491,11 +3491,11 @@ msgstr "Nastavení doplňků" #: mod/settings.php:767 mod/admin.php:2463 mod/admin.php:2464 msgid "Off" -msgstr "Vypnuto" +msgstr "Vyp" #: mod/settings.php:767 mod/admin.php:2463 mod/admin.php:2464 msgid "On" -msgstr "Zapnuto" +msgstr "Zap" #: mod/settings.php:774 msgid "Additional Features" @@ -3524,11 +3524,11 @@ msgstr "GNU Social (OStatus)" #: mod/settings.php:829 msgid "Email access is disabled on this site." -msgstr "Přístup k elektronické poště je na tomto serveru zakázán." +msgstr "Přístup k e-mailu je na tomto serveru zakázán." #: mod/settings.php:839 msgid "General Social Media Settings" -msgstr "General Social Media nastavení" +msgstr "Obecná nastavení sociálních sítí" #: mod/settings.php:840 msgid "Disable Content Warning" @@ -3833,7 +3833,7 @@ msgstr "Účet pro běžný osobní profil, který vyžaduje manuální potvrzen #: mod/settings.php:1062 mod/admin.php:1760 msgid "Soapbox Page" -msgstr "Stránka \"Soapbox\"" +msgstr "Propagační stránka" #: mod/settings.php:1063 msgid "" @@ -3851,7 +3851,7 @@ msgstr "Automaticky potvrzuje všechny žádosti o přidání kontaktu." #: mod/settings.php:1070 mod/admin.php:1762 msgid "Automatic Friend Page" -msgstr "Automatická stránka přítele" +msgstr "Stránka s automatickými přátely" #: mod/settings.php:1071 msgid "" @@ -3945,7 +3945,7 @@ msgstr "Povolit, abychom vás navrhovali jako přátelé pro nové členy?" #: mod/settings.php:1123 msgid "" "If you like, Friendica may suggest new members to add you as a contact." -msgstr "Pokud budete chtít, Friendica může nabízet novým členům, abi si Vás přidali jako kontakt." +msgstr "Pokud budete chtít, může Friendica nabízet novým členům, aby si Vás přidali jako kontakt." #: mod/settings.php:1127 msgid "Permit unknown people to send you private mail?" @@ -4078,7 +4078,7 @@ msgstr "Maximální počet žádostí o přátelství za den:" #: mod/settings.php:1208 mod/settings.php:1237 msgid "(to prevent spam abuse)" -msgstr "(Aby se zabránilo spamu)" +msgstr "(ay se zabránilo spamu)" #: mod/settings.php:1209 msgid "Default Post Permissions" @@ -4222,7 +4222,7 @@ msgstr "Zobrazit album" #: mod/videos.php:396 msgid "Recent Videos" -msgstr "Aktuální Videa" +msgstr "Aktuální videa" #: mod/videos.php:398 msgid "Upload New Videos" @@ -4535,7 +4535,7 @@ msgstr "Smazat tuto položku" msgid "" "On this page you can delete an item from your node. If the item is a top " "level posting, the entire thread will be deleted." -msgstr "Na této stránce můžete smazat pološku z Vašeho serveru. Pokud je položkou příspěvek nejvyššího stupně, bude smazáno celé vlákno." +msgstr "Na této stránce můžete smazat položku z Vašeho serveru. Pokud je položkou příspěvek nejvyššího stupně, bude smazáno celé vlákno." #: mod/admin.php:528 msgid "" @@ -6339,7 +6339,7 @@ msgstr "Vrátit z archívu" #: mod/contacts.php:831 msgid "Batch Actions" -msgstr "Dávkové (batch) akce" +msgstr "Souhrnné akce" #: mod/contacts.php:865 src/Model/Profile.php:894 msgid "Profile Details" diff --git a/view/lang/cs/strings.php b/view/lang/cs/strings.php index 9bdcd2ad27..32017d8653 100644 --- a/view/lang/cs/strings.php +++ b/view/lang/cs/strings.php @@ -14,7 +14,7 @@ $a->strings["Permission denied."] = "Přístup odmítnut."; $a->strings["Archives"] = "Archív"; $a->strings["show more"] = "zobrazit více"; $a->strings["Welcome "] = "Vítejte "; -$a->strings["Please upload a profile photo."] = "Prosím nahrejte profilovou fotografii"; +$a->strings["Please upload a profile photo."] = "Prosím nahrajte profilovou fotografii"; $a->strings["Welcome back "] = "Vítejte zpět "; $a->strings["The form security token was not correct. This probably happened because the form has been opened for too long (>3 hours) before submitting it."] = "Formulářový bezpečnostní token nebyl správný. To pravděpodobně nastalo kvůli tom, že formulář byl otevřen příliš dlouho (>3 hodiny) před jeho odesláním."; $a->strings["Daily posting limit of %d post reached. The post was rejected."] = [ @@ -39,11 +39,11 @@ $a->strings["%1\$s doesn't like %2\$s's %3\$s"] = "Uživateli %1\$s se nelíbí $a->strings["%1\$s attends %2\$s's %3\$s"] = "%1\$s se účastní %3\$s %2\$s"; $a->strings["%1\$s doesn't attend %2\$s's %3\$s"] = "%1\$s se neúčastní %3\$s %2\$s"; $a->strings["%1\$s attends maybe %2\$s's %3\$s"] = "%1\$s se možná účastní %3\$s %2\$s"; -$a->strings["%1\$s is now friends with %2\$s"] = "%1\$s je nyní přítel s %2\$s"; +$a->strings["%1\$s is now friends with %2\$s"] = "%1\$s je nyní přítel s uživatelem %2\$s"; $a->strings["%1\$s poked %2\$s"] = "%1\$s šťouchnul %2\$s"; -$a->strings["%1\$s tagged %2\$s's %3\$s with %4\$s"] = "%1\$s označil %3\$s %2\$s s %4\$s"; +$a->strings["%1\$s tagged %2\$s's %3\$s with %4\$s"] = "%1\$s označil/a %3\$s uživatele %2\$s jako %4\$s"; $a->strings["post/item"] = "příspěvek/položka"; -$a->strings["%1\$s marked %2\$s's %3\$s as favorite"] = "uživatel %1\$s označil %3\$s %2\$s jako oblíbené"; +$a->strings["%1\$s marked %2\$s's %3\$s as favorite"] = "%1\$s označil/a %3\$s uživatele %2\$s jako oblíbené"; $a->strings["Likes"] = "Libí se"; $a->strings["Dislikes"] = "Nelibí se"; $a->strings["Attending"] = [ @@ -120,8 +120,8 @@ $a->strings["Permission settings"] = "Nastavení oprávnění"; $a->strings["permissions"] = "oprávnění"; $a->strings["Public post"] = "Veřejný příspěvek"; $a->strings["Preview"] = "Náhled"; -$a->strings["Post to Groups"] = "Zveřejnit na Groups"; -$a->strings["Post to Contacts"] = "Zveřejnit na Groups"; +$a->strings["Post to Groups"] = "Zveřejnit ve skupinách"; +$a->strings["Post to Contacts"] = "Zveřejnit v kontaktech"; $a->strings["Private post"] = "Soukromý příspěvek"; $a->strings["Message"] = "Zpráva"; $a->strings["Browser"] = "Prohlížeč"; @@ -227,7 +227,7 @@ $a->strings["%d Contact"] = [ $a->strings["View Contacts"] = "Zobrazit kontakty"; $a->strings["Save"] = "Uložit"; $a->strings["Follow"] = "Sledovat"; -$a->strings["Search"] = "Vyhledávání"; +$a->strings["Search"] = "Hledat"; $a->strings["@name, !forum, #tags, content"] = "@jméno, !fórum, #štítky, obsah"; $a->strings["Full Text"] = "Celý text"; $a->strings["Tags"] = "Štítky:"; @@ -804,16 +804,16 @@ $a->strings["No name"] = "Bez názvu"; $a->strings["Remove authorization"] = "Odstranit oprávnění"; $a->strings["No Addon settings configured"] = "Žádná nastavení doplňků nenakonfigurována"; $a->strings["Addon Settings"] = "Nastavení doplňků"; -$a->strings["Off"] = "Vypnuto"; -$a->strings["On"] = "Zapnuto"; +$a->strings["Off"] = "Vyp"; +$a->strings["On"] = "Zap"; $a->strings["Additional Features"] = "Další Funkčnosti"; $a->strings["Diaspora"] = "Diaspora"; $a->strings["enabled"] = "povoleno"; $a->strings["disabled"] = "zakázáno"; $a->strings["Built-in support for %s connectivity is %s"] = "Vestavěná podpora pro připojení s %s je %s"; $a->strings["GNU Social (OStatus)"] = "GNU Social (OStatus)"; -$a->strings["Email access is disabled on this site."] = "Přístup k elektronické poště je na tomto serveru zakázán."; -$a->strings["General Social Media Settings"] = "General Social Media nastavení"; +$a->strings["Email access is disabled on this site."] = "Přístup k e-mailu je na tomto serveru zakázán."; +$a->strings["General Social Media Settings"] = "Obecná nastavení sociálních sítí"; $a->strings["Disable Content Warning"] = "Vypnout varování o obsahu"; $a->strings["Users on networks like Mastodon or Pleroma are able to set a content warning field which collapse their post by default. This disables the automatic collapsing and sets the content warning as the post title. Doesn't affect any other content filtering you eventually set up."] = "Uživatelé na sítích, jako je Mastodon nebo Pleroma, si mohou nastavit pole s varováním o obsahu, která ve výchozim nastavení skryje jejich příspěvek. Tato možnost vypíná automatické skrývání a nastavuje varování o obsahu jako titulek příspěvku. Toto se netýká žádného dalšího filtrování obsahu, které se rozhodnete nastavit."; $a->strings["Disable intelligent shortening"] = "Vypnout inteligentní zkracování"; @@ -881,11 +881,11 @@ $a->strings["Community Forum"] = "Komunitní fórum"; $a->strings["Account for community discussions."] = "Účet pro komunitní diskuze."; $a->strings["Normal Account Page"] = "Normální stránka účtu"; $a->strings["Account for a regular personal profile that requires manual approval of \"Friends\" and \"Followers\"."] = "Účet pro běžný osobní profil, který vyžaduje manuální potvrzení \"Přátel\" a \"Sledovatelů\"."; -$a->strings["Soapbox Page"] = "Stránka \"Soapbox\""; +$a->strings["Soapbox Page"] = "Propagační stránka"; $a->strings["Account for a public profile that automatically approves contact requests as \"Followers\"."] = "Účet pro veřejný profil, který vyžaduje manuální potvrzení \"Přátel\" a \"Sledovatelů\"."; $a->strings["Public Forum"] = "Veřejné fórum"; $a->strings["Automatically approves all contact requests."] = "Automaticky potvrzuje všechny žádosti o přidání kontaktu."; -$a->strings["Automatic Friend Page"] = "Automatická stránka přítele"; +$a->strings["Automatic Friend Page"] = "Stránka s automatickými přátely"; $a->strings["Account for a popular profile that automatically approves contact requests as \"Friends\"."] = "Účet pro populární profil, který automaticky potvrzuje žádosti o přidání kontaktu jako \"Přátele\"."; $a->strings["Private Forum [Experimental]"] = "Soukromé fórum [Experimentální]"; $a->strings["Requires manual approval of contact requests."] = "Vyžaduje manuální potvrzení žádostí o přidání kontaktu."; @@ -904,7 +904,7 @@ $a->strings["Your contacts may write posts on your profile wall. These posts wil $a->strings["Allow friends to tag your posts?"] = "Povolit přátelům označovat Vaše příspěvky?"; $a->strings["Your contacts can add additional tags to your posts."] = "Vaše kontakty mohou přidávat k Vašim příspěvkům dodatečné štítky."; $a->strings["Allow us to suggest you as a potential friend to new members?"] = "Povolit, abychom vás navrhovali jako přátelé pro nové členy?"; -$a->strings["If you like, Friendica may suggest new members to add you as a contact."] = "Pokud budete chtít, Friendica může nabízet novým členům, abi si Vás přidali jako kontakt."; +$a->strings["If you like, Friendica may suggest new members to add you as a contact."] = "Pokud budete chtít, může Friendica nabízet novým členům, aby si Vás přidali jako kontakt."; $a->strings["Permit unknown people to send you private mail?"] = "Povolit neznámým lidem Vám zasílat soukromé zprávy?"; $a->strings["Friendica network users may send you private messages even if they are not in your contact list."] = "Uživatelé sítě Friendica Vám mohou posílat soukromé zprávy, i pokud nejsou ve Vašich kontaktech."; $a->strings["Profile is not published."] = "Profil není zveřejněn."; @@ -936,7 +936,7 @@ $a->strings["Default Post Location:"] = "Výchozí umístění příspěvků:"; $a->strings["Use Browser Location:"] = "Používat umístění dle prohlížeče:"; $a->strings["Security and Privacy Settings"] = "Nastavení zabezpečení a soukromí"; $a->strings["Maximum Friend Requests/Day:"] = "Maximální počet žádostí o přátelství za den:"; -$a->strings["(to prevent spam abuse)"] = "(Aby se zabránilo spamu)"; +$a->strings["(to prevent spam abuse)"] = "(ay se zabránilo spamu)"; $a->strings["Default Post Permissions"] = "Výchozí oprávnění pro příspěvek"; $a->strings["(click to open/close)"] = "(Klikněte pro otevření/zavření)"; $a->strings["Show to Groups"] = "Zobrazit ve Skupinách"; @@ -971,7 +971,7 @@ $a->strings["Delete Video"] = "Odstranit video"; $a->strings["No videos selected"] = "Není vybráno žádné video"; $a->strings["Access to this item is restricted."] = "Přístup k této položce je omezen."; $a->strings["View Album"] = "Zobrazit album"; -$a->strings["Recent Videos"] = "Aktuální Videa"; +$a->strings["Recent Videos"] = "Aktuální videa"; $a->strings["Upload New Videos"] = "Nahrát nová videa"; $a->strings["Theme settings updated."] = "Nastavení motivu bylo aktualizováno."; $a->strings["Information"] = "Informace"; @@ -1050,7 +1050,7 @@ $a->strings["%s total blocked contact"] = [ ]; $a->strings["URL of the remote contact to block."] = "Adresa URL vzdáleného kontaktu k zablokování."; $a->strings["Delete this Item"] = "Smazat tuto položku"; -$a->strings["On this page you can delete an item from your node. If the item is a top level posting, the entire thread will be deleted."] = "Na této stránce můžete smazat pološku z Vašeho serveru. Pokud je položkou příspěvek nejvyššího stupně, bude smazáno celé vlákno."; +$a->strings["On this page you can delete an item from your node. If the item is a top level posting, the entire thread will be deleted."] = "Na této stránce můžete smazat položku z Vašeho serveru. Pokud je položkou příspěvek nejvyššího stupně, bude smazáno celé vlákno."; $a->strings["You need to know the GUID of the item. You can find it e.g. by looking at the display URL. The last part of http://example.com/display/123456 is the GUID, here 123456."] = "Budete muset znát číslo GUID položky. Můžete jej najít např. v adrese URL. Poslední část adresy http://example.com/display/123456 je GUID, v tomto případě 123456"; $a->strings["GUID"] = "GUID"; $a->strings["The GUID of the item you want to delete."] = "Číslo GUID položky, kterou chcete smazat"; @@ -1447,7 +1447,7 @@ $a->strings["Results for: %s"] = "Výsledky pro: %s"; $a->strings["Find"] = "Najít"; $a->strings["Archive"] = "Archivovat"; $a->strings["Unarchive"] = "Vrátit z archívu"; -$a->strings["Batch Actions"] = "Dávkové (batch) akce"; +$a->strings["Batch Actions"] = "Souhrnné akce"; $a->strings["Profile Details"] = "Detaily profilu"; $a->strings["View all contacts"] = "Zobrazit všechny kontakty"; $a->strings["View all common friends"] = "Zobrazit všechny společné přátele"; From 1ffe0cfd818ad48f7c227915d3abf68d26d8a06c Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Sat, 7 Jul 2018 16:15:03 +0200 Subject: [PATCH 56/65] Added Lock Unittests & Bugfixings Added Redis Lock Unittests Added Memcached Lock Unittests Fixed a bug in dba Fixed a bug in RedisLock --- .travis.yml | 4 ++ include/dba.php | 2 +- src/Core/Cache/AbstractCacheDriver.php | 1 + src/Core/Cache/RedisCacheDriver.php | 31 +++++-------- ...rTest.php => ArrayCacheLockDriverTest.php} | 4 +- .../src/Core/Lock/DatabaseLockDriverTest.php | 45 +------------------ tests/src/Core/Lock/LockTest.php | 15 +++++-- .../Lock/MemcachedCacheLockDriverTest.php | 40 +++++++++++++++++ .../Core/Lock/RedisCacheLockDriverTest.php | 40 +++++++++++++++++ .../src/Core/Lock/SemaphoreLockDriverTest.php | 2 +- 10 files changed, 114 insertions(+), 70 deletions(-) rename tests/src/Core/Lock/{CacheLockDriverTest.php => ArrayCacheLockDriverTest.php} (89%) create mode 100644 tests/src/Core/Lock/MemcachedCacheLockDriverTest.php create mode 100644 tests/src/Core/Lock/RedisCacheLockDriverTest.php diff --git a/.travis.yml b/.travis.yml index 78c29817db..6e7ac1c2e0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,8 @@ php: services: - mysql + - redis-server + - memcached env: - MYSQL_HOST=localhost MYSQL_PORT=3306 MYSQL_USERNAME=travis MYSQL_PASSWORD= MYSQL_DATABASE=test @@ -17,3 +19,5 @@ install: before_script: - mysql -e 'CREATE DATABASE IF NOT EXISTS test;' - mysql -utravis test < database.sql + - echo "extension=redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini + - echo "extension=memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini diff --git a/include/dba.php b/include/dba.php index 9d828f8b44..061f5399c7 100644 --- a/include/dba.php +++ b/include/dba.php @@ -1109,7 +1109,7 @@ class dba { // Split the SQL queries in chunks of 100 values // We do the $i stuff here to make the code better readable - $i = $counter[$key_table][$key_condition]; + $i = isset($counter[$key_table][$key_condition]) ? $counter[$key_table][$key_condition] : 0; if (isset($compacted[$key_table][$key_condition][$i]) && count($compacted[$key_table][$key_condition][$i]) > 100) { ++$i; } diff --git a/src/Core/Cache/AbstractCacheDriver.php b/src/Core/Cache/AbstractCacheDriver.php index 417accdce7..15b822dc3b 100644 --- a/src/Core/Cache/AbstractCacheDriver.php +++ b/src/Core/Cache/AbstractCacheDriver.php @@ -18,6 +18,7 @@ abstract class AbstractCacheDriver extends BaseObject * @return string The cache key used for the cache */ protected function getCacheKey($key) { + // We fetch with the hostname as key to avoid problems with other applications return self::getApp()->get_hostname() . ":" . $key; } } diff --git a/src/Core/Cache/RedisCacheDriver.php b/src/Core/Cache/RedisCacheDriver.php index 67df8e8fee..c0006822d5 100644 --- a/src/Core/Cache/RedisCacheDriver.php +++ b/src/Core/Cache/RedisCacheDriver.php @@ -35,15 +35,12 @@ class RedisCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver $return = null; $cachekey = $this->getCacheKey($key); - // We fetch with the hostname as key to avoid problems with other applications $cached = $this->redis->get($cachekey); - - // @see http://php.net/manual/en/redis.get.php#84275 - if (is_bool($cached) || is_double($cached) || is_long($cached)) { - return $return; + if ($cached === false && !$this->redis->exists($cachekey)) { + return null; } - $value = @unserialize($cached); + $value = json_decode($cached); // Only return a value if the serialized value is valid. // We also check if the db entry is a serialized @@ -59,17 +56,18 @@ class RedisCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver { $cachekey = $this->getCacheKey($key); - // We store with the hostname as key to avoid problems with other applications + $cached = json_encode($value); + if ($ttl > 0) { return $this->redis->setex( $cachekey, time() + $ttl, - serialize($value) + $cached ); } else { return $this->redis->set( $cachekey, - serialize($value) + $cached ); } } @@ -81,7 +79,7 @@ class RedisCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver public function clear() { - return true; + return $this->redis->flushAll(); } @@ -91,10 +89,7 @@ class RedisCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver public function add($key, $value, $ttl = Cache::FIVE_MINUTES) { $cachekey = $this->getCacheKey($key); - - if (!is_int($value)) { - $value = serialize($value); - } + $cached = json_encode($value); return $this->redis->setnx($cachekey, $value); } @@ -106,16 +101,14 @@ class RedisCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver { $cachekey = $this->getCacheKey($key); - if (!is_int($newValue)) { - $newValue = serialize($newValue); - } + $newCached = json_encode($newValue); $this->redis->watch($cachekey); // If the old value isn't what we expected, somebody else changed the key meanwhile - if ($this->get($cachekey) === $oldValue) { + if ($this->get($key) === $oldValue) { if ($ttl > 0) { $result = $this->redis->multi() - ->setex($cachekey, $ttl, $newValue) + ->setex($cachekey, $ttl, $newCached) ->exec(); } else { $result = $this->redis->multi() diff --git a/tests/src/Core/Lock/CacheLockDriverTest.php b/tests/src/Core/Lock/ArrayCacheLockDriverTest.php similarity index 89% rename from tests/src/Core/Lock/CacheLockDriverTest.php rename to tests/src/Core/Lock/ArrayCacheLockDriverTest.php index a089059725..0e58bf49e3 100644 --- a/tests/src/Core/Lock/CacheLockDriverTest.php +++ b/tests/src/Core/Lock/ArrayCacheLockDriverTest.php @@ -6,7 +6,7 @@ namespace Friendica\Test\src\Core\Lock; use Friendica\Core\Cache\ArrayCache; use Friendica\Core\Lock\CacheLockDriver; -class CacheLockDriverTest extends LockTest +class ArrayCacheLockDriverTest extends LockTest { /** * @var \Friendica\Core\Cache\IMemoryCacheDriver @@ -24,4 +24,4 @@ class CacheLockDriverTest extends LockTest $this->cache->clear(); parent::tearDown(); } -} \ No newline at end of file +} diff --git a/tests/src/Core/Lock/DatabaseLockDriverTest.php b/tests/src/Core/Lock/DatabaseLockDriverTest.php index a80ff4c37c..f55ab0f9e2 100644 --- a/tests/src/Core/Lock/DatabaseLockDriverTest.php +++ b/tests/src/Core/Lock/DatabaseLockDriverTest.php @@ -11,49 +11,6 @@ use PHPUnit_Extensions_Database_DB_IDatabaseConnection; class DatabaseLockDriverTest extends LockTest { - use TestCaseTrait; - - /** - * Get database connection. - * - * This function is executed before each test in order to get a database connection that can be used by tests. - * If no prior connection is available, it tries to create one using the USER, PASS and DB environment variables. - * - * If it could not connect to the database, the test is skipped. - * - * @return PHPUnit_Extensions_Database_DB_IDatabaseConnection - * @see https://phpunit.de/manual/5.7/en/database.html - */ - protected function getConnection() - { - if (!dba::$connected) { - dba::connect('localhost', getenv('USER'), getenv('PASS'), getenv('DB')); - - if (dba::$connected) { - $app = get_app(); - // We need to do this in order to disable logging - $app->module = 'install'; - - // Create database structure - DBStructure::update(false, true, true); - } else { - $this->markTestSkipped('Could not connect to the database.'); - } - } - - return $this->createDefaultDBConnection(dba::get_db(), getenv('DB')); - } - - /** - * Get dataset to populate the database with. - * @return YamlDataSet - * @see https://phpunit.de/manual/5.7/en/database.html - */ - protected function getDataSet() - { - return new YamlDataSet(__DIR__ . '/../../../datasets/api.yml'); - } - protected function getInstance() { return new DatabaseLockDriver(); @@ -64,4 +21,4 @@ class DatabaseLockDriverTest extends LockTest dba::delete('locks', [ 'id > 0']); parent::tearDown(); } -} \ No newline at end of file +} diff --git a/tests/src/Core/Lock/LockTest.php b/tests/src/Core/Lock/LockTest.php index c8c0c32ae2..a120edeb0c 100644 --- a/tests/src/Core/Lock/LockTest.php +++ b/tests/src/Core/Lock/LockTest.php @@ -4,9 +4,10 @@ namespace Friendica\Test\src\Core\Lock; use Friendica\App; use Friendica\Core\Config; +use Friendica\Test\DatabaseTest; use PHPUnit\Framework\TestCase; -abstract class LockTest extends TestCase +abstract class LockTest extends DatabaseTest { /** * @var \Friendica\Core\Lock\ILockDriver @@ -58,6 +59,10 @@ abstract class LockTest extends TestCase $this->instance->acquireLock('bar', 1); $this->instance->acquireLock('nice', 1); + $this->assertTrue($this->instance->isLocked('foo')); + $this->assertTrue($this->instance->isLocked('bar')); + $this->assertTrue($this->instance->isLocked('nice')); + $this->instance->releaseAll(); $this->assertFalse($this->instance->isLocked('foo')); @@ -72,9 +77,13 @@ abstract class LockTest extends TestCase $this->instance->releaseLock('foo'); + $this->assertFalse($this->instance->isLocked('foo')); + $this->assertTrue($this->instance->isLocked('bar')); + $this->assertTrue($this->instance->isLocked('nice')); + $this->instance->releaseAll(); $this->assertFalse($this->instance->isLocked('bar')); - $this->assertFalse($this->instance->isLocked('#/$%§')); + $this->assertFalse($this->instance->isLocked('nice')); } -} \ No newline at end of file +} diff --git a/tests/src/Core/Lock/MemcachedCacheLockDriverTest.php b/tests/src/Core/Lock/MemcachedCacheLockDriverTest.php new file mode 100644 index 0000000000..678c54c77a --- /dev/null +++ b/tests/src/Core/Lock/MemcachedCacheLockDriverTest.php @@ -0,0 +1,40 @@ +cache = CacheDriverFactory::create('memcached'); + } catch (\Exception $exception) { + print "Redis - TestCase failed: " . $exception->getMessage(); + throw new \Exception(); + } + return new CacheLockDriver($this->cache); + } else { + $this->markTestSkipped('Redis driver isn\'t available'); + return null; + } + } + + public function tearDown() + { + if (class_exists('Redis')) { + $this->cache->clear(); + } + parent::tearDown(); + } +} diff --git a/tests/src/Core/Lock/RedisCacheLockDriverTest.php b/tests/src/Core/Lock/RedisCacheLockDriverTest.php new file mode 100644 index 0000000000..82d9b50def --- /dev/null +++ b/tests/src/Core/Lock/RedisCacheLockDriverTest.php @@ -0,0 +1,40 @@ +cache = CacheDriverFactory::create('redis'); + } catch (\Exception $exception) { + print "Redis - TestCase failed: " . $exception->getMessage(); + throw new \Exception(); + } + return new CacheLockDriver($this->cache); + } else { + $this->markTestSkipped('Redis driver isn\'t available'); + return null; + } + } + + public function tearDown() + { + if (class_exists('Redis')) { + $this->cache->clear(); + } + parent::tearDown(); + } +} diff --git a/tests/src/Core/Lock/SemaphoreLockDriverTest.php b/tests/src/Core/Lock/SemaphoreLockDriverTest.php index 56c96458f2..48c2aff4df 100644 --- a/tests/src/Core/Lock/SemaphoreLockDriverTest.php +++ b/tests/src/Core/Lock/SemaphoreLockDriverTest.php @@ -23,4 +23,4 @@ class SemaphoreLockDriverTest extends LockTest $this->semaphoreLockDriver->releaseAll(); parent::tearDown(); } -} \ No newline at end of file +} From f61aa2a3ee087dd5160cf904fdcf327fe49f31f7 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Sat, 7 Jul 2018 17:59:22 +0200 Subject: [PATCH 57/65] fixed locks in database.sql --- database.sql | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/database.sql b/database.sql index b3d8f5dd05..e51f2a1e9b 100644 --- a/database.sql +++ b/database.sql @@ -576,8 +576,10 @@ CREATE TABLE IF NOT EXISTS `locks` ( `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', `name` varchar(128) NOT NULL DEFAULT '' COMMENT '', `locked` boolean NOT NULL DEFAULT '0' COMMENT '', + `expires` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'datetime of lock expiration', `pid` int unsigned NOT NULL DEFAULT 0 COMMENT 'Process ID', - PRIMARY KEY(`id`) + PRIMARY KEY(`id`), + INDEX `name_expires` (`name`,`expires`) ) DEFAULT COLLATE utf8mb4_general_ci COMMENT=''; -- From 6ecaa5b15a99aa24a771e257d86dd94621b36466 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Sat, 7 Jul 2018 18:12:17 +0200 Subject: [PATCH 58/65] copy&paste error for memcached unittest --- tests/src/Core/Lock/MemcachedCacheLockDriverTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/src/Core/Lock/MemcachedCacheLockDriverTest.php b/tests/src/Core/Lock/MemcachedCacheLockDriverTest.php index 678c54c77a..e08358ce38 100644 --- a/tests/src/Core/Lock/MemcachedCacheLockDriverTest.php +++ b/tests/src/Core/Lock/MemcachedCacheLockDriverTest.php @@ -20,19 +20,19 @@ class MemcachedCacheLockDriverTest extends LockTest try { $this->cache = CacheDriverFactory::create('memcached'); } catch (\Exception $exception) { - print "Redis - TestCase failed: " . $exception->getMessage(); + print "Memcached - TestCase failed: " . $exception->getMessage(); throw new \Exception(); } return new CacheLockDriver($this->cache); } else { - $this->markTestSkipped('Redis driver isn\'t available'); + $this->markTestSkipped('Memcached driver isn\'t available'); return null; } } public function tearDown() { - if (class_exists('Redis')) { + if (class_exists('Memcached')) { $this->cache->clear(); } parent::tearDown(); From f95c42080114e6d8771bf7d278cb8b46ffb9bafd Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Sat, 7 Jul 2018 18:39:33 +0200 Subject: [PATCH 59/65] bug in redis delete function --- src/Core/Cache/RedisCacheDriver.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Core/Cache/RedisCacheDriver.php b/src/Core/Cache/RedisCacheDriver.php index c0006822d5..70412fd215 100644 --- a/src/Core/Cache/RedisCacheDriver.php +++ b/src/Core/Cache/RedisCacheDriver.php @@ -74,7 +74,8 @@ class RedisCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver public function delete($key) { - return $this->redis->delete($key); + $cachekey = $this->getCacheKey($key); + return ($this->redis->delete($cachekey) > 0); } public function clear() From 1dafaa69c5703daf7840a62b50f56df1ccb9c5f7 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Sat, 7 Jul 2018 18:43:55 +0200 Subject: [PATCH 60/65] bug in memcached clear function --- src/Core/Cache/MemcachedCacheDriver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/Cache/MemcachedCacheDriver.php b/src/Core/Cache/MemcachedCacheDriver.php index 819cf71c5c..dda6411a96 100644 --- a/src/Core/Cache/MemcachedCacheDriver.php +++ b/src/Core/Cache/MemcachedCacheDriver.php @@ -77,7 +77,7 @@ class MemcachedCacheDriver extends AbstractCacheDriver implements IMemoryCacheDr public function clear() { - return true; + return $this->memcached->flush(); } /** From 80a4e6263fd53f83a710d2a2e6c57baae38cb14b Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Sat, 7 Jul 2018 19:46:16 +0200 Subject: [PATCH 61/65] Added Unittests for cache fixed Lock & Cache bugs --- src/Core/Cache/ArrayCache.php | 2 +- src/Core/Cache/DatabaseCacheDriver.php | 10 +- src/Core/Cache/ICacheDriver.php | 3 +- src/Core/Cache/MemcacheCacheDriver.php | 8 +- src/Core/Cache/MemcachedCacheDriver.php | 10 +- src/Core/Cache/RedisCacheDriver.php | 13 ++- src/Core/Lock/CacheLockDriver.php | 5 +- src/Core/Lock/DatabaseLockDriver.php | 9 +- src/Core/Lock/ILockDriver.php | 4 +- src/Core/Lock/SemaphoreLockDriver.php | 5 +- tests/src/Core/Cache/ArrayCacheDriverTest.php | 32 ++++++ tests/src/Core/Cache/CacheTest.php | 106 ++++++++++++++++++ .../Core/Cache/DatabaseCacheDriverTest.php | 25 +++++ .../Core/Cache/MemcachedCacheDriverTest.php | 39 +++++++ tests/src/Core/Cache/RedisCacheDriverTest.php | 39 +++++++ .../Core/Lock/ArrayCacheLockDriverTest.php | 6 + tests/src/Core/Lock/LockTest.php | 20 ++++ .../src/Core/Lock/SemaphoreLockDriverTest.php | 6 + 18 files changed, 317 insertions(+), 25 deletions(-) create mode 100644 tests/src/Core/Cache/ArrayCacheDriverTest.php create mode 100644 tests/src/Core/Cache/CacheTest.php create mode 100644 tests/src/Core/Cache/DatabaseCacheDriverTest.php create mode 100644 tests/src/Core/Cache/MemcachedCacheDriverTest.php create mode 100644 tests/src/Core/Cache/RedisCacheDriverTest.php diff --git a/src/Core/Cache/ArrayCache.php b/src/Core/Cache/ArrayCache.php index ec9f3a2577..b198287148 100644 --- a/src/Core/Cache/ArrayCache.php +++ b/src/Core/Cache/ArrayCache.php @@ -51,7 +51,7 @@ class ArrayCache extends AbstractCacheDriver implements IMemoryCacheDriver /** * (@inheritdoc) */ - public function clear() + public function clear($outdated = true) { $this->cachedData = []; return true; diff --git a/src/Core/Cache/DatabaseCacheDriver.php b/src/Core/Cache/DatabaseCacheDriver.php index 5c71fb1962..059fef3290 100644 --- a/src/Core/Cache/DatabaseCacheDriver.php +++ b/src/Core/Cache/DatabaseCacheDriver.php @@ -37,7 +37,7 @@ class DatabaseCacheDriver extends AbstractCacheDriver implements ICacheDriver { $fields = [ 'v' => serialize($value), - 'expires' => DateTimeFormat::utc('now + ' . $ttl . ' seconds'), + 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds'), 'updated' => DateTimeFormat::utcNow() ]; @@ -49,8 +49,12 @@ class DatabaseCacheDriver extends AbstractCacheDriver implements ICacheDriver return dba::delete('cache', ['k' => $key]); } - public function clear() + public function clear($outdated = true) { - return dba::delete('cache', ['`expires` < NOW()']); + if ($outdated) { + return dba::delete('cache', ['`expires` < NOW()']); + } else { + return dba::delete('cache', ['`k` IS NOT NULL ']); + } } } diff --git a/src/Core/Cache/ICacheDriver.php b/src/Core/Cache/ICacheDriver.php index ced7b4e216..e83b921c6a 100644 --- a/src/Core/Cache/ICacheDriver.php +++ b/src/Core/Cache/ICacheDriver.php @@ -42,8 +42,9 @@ interface ICacheDriver /** * Remove outdated data from the cache + * @param boolean $outdated just remove outdated values * * @return bool */ - public function clear(); + public function clear($outdated = true); } diff --git a/src/Core/Cache/MemcacheCacheDriver.php b/src/Core/Cache/MemcacheCacheDriver.php index af7e5ab0e2..cd12be8ecd 100644 --- a/src/Core/Cache/MemcacheCacheDriver.php +++ b/src/Core/Cache/MemcacheCacheDriver.php @@ -96,9 +96,13 @@ class MemcacheCacheDriver extends AbstractCacheDriver implements IMemoryCacheDri /** * (@inheritdoc) */ - public function clear() + public function clear($outdated = true) { - return $this->memcache->flush(); + if ($outdated) { + return true; + } else { + return $this->memcache->flush(); + } } /** diff --git a/src/Core/Cache/MemcachedCacheDriver.php b/src/Core/Cache/MemcachedCacheDriver.php index dda6411a96..d4aab15c92 100644 --- a/src/Core/Cache/MemcachedCacheDriver.php +++ b/src/Core/Cache/MemcachedCacheDriver.php @@ -58,7 +58,7 @@ class MemcachedCacheDriver extends AbstractCacheDriver implements IMemoryCacheDr return $this->memcached->set( $cachekey, $value, - time() + $ttl + $ttl ); } else { return $this->memcached->set( @@ -75,9 +75,13 @@ class MemcachedCacheDriver extends AbstractCacheDriver implements IMemoryCacheDr return $this->memcached->delete($cachekey); } - public function clear() + public function clear($outdated = true) { - return $this->memcached->flush(); + if ($outdated) { + return true; + } else { + return $this->memcached->flush(); + } } /** diff --git a/src/Core/Cache/RedisCacheDriver.php b/src/Core/Cache/RedisCacheDriver.php index 70412fd215..223c2b8a94 100644 --- a/src/Core/Cache/RedisCacheDriver.php +++ b/src/Core/Cache/RedisCacheDriver.php @@ -61,7 +61,7 @@ class RedisCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver if ($ttl > 0) { return $this->redis->setex( $cachekey, - time() + $ttl, + $ttl, $cached ); } else { @@ -78,12 +78,15 @@ class RedisCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver return ($this->redis->delete($cachekey) > 0); } - public function clear() + public function clear($outdated = true) { - return $this->redis->flushAll(); + if ($outdated) { + return true; + } else { + return $this->redis->flushAll(); + } } - /** * (@inheritdoc) */ @@ -92,7 +95,7 @@ class RedisCacheDriver extends AbstractCacheDriver implements IMemoryCacheDriver $cachekey = $this->getCacheKey($key); $cached = json_encode($value); - return $this->redis->setnx($cachekey, $value); + return $this->redis->setnx($cachekey, $cached); } /** diff --git a/src/Core/Lock/CacheLockDriver.php b/src/Core/Lock/CacheLockDriver.php index ccbbb8a350..18d441ffea 100644 --- a/src/Core/Lock/CacheLockDriver.php +++ b/src/Core/Lock/CacheLockDriver.php @@ -2,6 +2,7 @@ namespace Friendica\Core\Lock; +use Friendica\Core\Cache; use Friendica\Core\Cache\IMemoryCacheDriver; class CacheLockDriver extends AbstractLockDriver @@ -24,7 +25,7 @@ class CacheLockDriver extends AbstractLockDriver /** * (@inheritdoc) */ - public function acquireLock($key, $timeout = 120) + public function acquireLock($key, $timeout = 120, $ttl = Cache::FIVE_MINUTES) { $got_lock = false; $start = time(); @@ -43,7 +44,7 @@ class CacheLockDriver extends AbstractLockDriver // At first initialize it with "0" $this->cache->add($cachekey, 0); // Now the value has to be "0" because otherwise the key was used by another process meanwhile - if ($this->cache->compareSet($cachekey, 0, getmypid(), 300)) { + if ($this->cache->compareSet($cachekey, 0, getmypid(), $ttl)) { $got_lock = true; $this->markAcquire($key); } diff --git a/src/Core/Lock/DatabaseLockDriver.php b/src/Core/Lock/DatabaseLockDriver.php index 6f4b942a4d..fc057c6b55 100644 --- a/src/Core/Lock/DatabaseLockDriver.php +++ b/src/Core/Lock/DatabaseLockDriver.php @@ -3,6 +3,7 @@ namespace Friendica\Core\Lock; use dba; +use Friendica\Core\Cache; use Friendica\Database\DBM; use Friendica\Util\DateTimeFormat; @@ -14,7 +15,7 @@ class DatabaseLockDriver extends AbstractLockDriver /** * (@inheritdoc) */ - public function acquireLock($key, $timeout = 120) + public function acquireLock($key, $timeout = 120, $ttl = Cache::FIVE_MINUTES) { $got_lock = false; $start = time(); @@ -28,16 +29,14 @@ class DatabaseLockDriver extends AbstractLockDriver // We want to lock something that was already locked by us? So we got the lock. if ($lock['pid'] == getmypid()) { $got_lock = true; - $this->markAcquire($key); } } if (!$lock['locked']) { - dba::update('locks', ['locked' => true, 'pid' => getmypid(), 'expires' => DateTimeFormat::utc('now + 300seconds')], ['name' => $key]); + dba::update('locks', ['locked' => true, 'pid' => getmypid(), 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds')], ['name' => $key]); $got_lock = true; - $this->markAcquire($key); } } else { - dba::insert('locks', ['name' => $key, 'locked' => true, 'pid' => getmypid(), 'expires' => DateTimeFormat::utc('now + 300seconds')]); + dba::insert('locks', ['name' => $key, 'locked' => true, 'pid' => getmypid(), 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds')]); $got_lock = true; $this->markAcquire($key); } diff --git a/src/Core/Lock/ILockDriver.php b/src/Core/Lock/ILockDriver.php index cd54cc03c3..a255f68345 100644 --- a/src/Core/Lock/ILockDriver.php +++ b/src/Core/Lock/ILockDriver.php @@ -1,6 +1,7 @@ cache = new ArrayCache(); + return $this->cache; + } + + public function tearDown() + { + $this->cache->clear(); + parent::tearDown(); + } + + public function testTTL() + { + // Array Cache doesn't support TTL + return true; + } +} diff --git a/tests/src/Core/Cache/CacheTest.php b/tests/src/Core/Cache/CacheTest.php new file mode 100644 index 0000000000..419e0cd2bd --- /dev/null +++ b/tests/src/Core/Cache/CacheTest.php @@ -0,0 +1,106 @@ +instance = $this->getInstance(); + + // Reusable App object + $this->app = new App(__DIR__.'/../'); + $a = $this->app; + + // Default config + Config::set('config', 'hostname', 'localhost'); + Config::set('system', 'throttle_limit_day', 100); + Config::set('system', 'throttle_limit_week', 100); + Config::set('system', 'throttle_limit_month', 100); + Config::set('system', 'theme', 'system_theme'); + } + + function testSimple() { + $this->assertNull($this->instance->get('value1')); + + $value='foobar'; + $this->instance->set('value1', $value); + $received=$this->instance->get('value1'); + $this->assertEquals($value, $received, 'Value received from cache not equal to the original'); + $value='ipsum lorum'; + $this->instance->set('value1', $value); + $received=$this->instance->get('value1'); + $this->assertEquals($value, $received, 'Value not overwritten by second set'); + + $value2='foobar'; + $this->instance->set('value2', $value2); + $received2=$this->instance->get('value2'); + $this->assertEquals($value, $received, 'Value changed while setting other variable'); + $this->assertEquals($value2, $received2, 'Second value not equal to original'); + + $this->assertNull($this->instance->get('not_set'), 'Unset value not equal to null'); + + $this->assertTrue($this->instance->delete('value1')); + $this->assertNull($this->instance->get('value1')); + } + + function testClear() { + $value='ipsum lorum'; + $this->instance->set('1_value1', $value . '1'); + $this->instance->set('1_value2', $value . '2'); + $this->instance->set('2_value1', $value . '3'); + $this->instance->set('3_value1', $value . '4'); + + $this->assertEquals([ + '1_value1' => 'ipsum lorum1', + '1_value2' => 'ipsum lorum2', + '2_value1' => 'ipsum lorum3', + '3_value1' => 'ipsum lorum4', + ], [ + '1_value1' => $this->instance->get('1_value1'), + '1_value2' => $this->instance->get('1_value2'), + '2_value1' => $this->instance->get('2_value1'), + '3_value1' => $this->instance->get('3_value1'), + ]); + + $this->assertTrue($this->instance->clear(false)); + + $this->assertEquals([ + '1_value1' => null, + '1_value2' => null, + '2_value1' => null, + '3_value1' => null, + ], [ + '1_value1' => $this->instance->get('1_value1'), + '1_value2' => $this->instance->get('1_value2'), + '2_value1' => $this->instance->get('2_value1'), + '3_value1' => $this->instance->get('3_value1'), + ]); + } + + function testTTL() { + $this->assertNull($this->instance->get('value1')); + + $value='foobar'; + $this->instance->set('value1', $value, 1); + $received=$this->instance->get('value1'); + $this->assertEquals($value, $received, 'Value received from cache not equal to the original'); + + sleep(2); + + $this->assertNull($this->instance->get('value1')); + } +} diff --git a/tests/src/Core/Cache/DatabaseCacheDriverTest.php b/tests/src/Core/Cache/DatabaseCacheDriverTest.php new file mode 100644 index 0000000000..ed2e47fb47 --- /dev/null +++ b/tests/src/Core/Cache/DatabaseCacheDriverTest.php @@ -0,0 +1,25 @@ +cache = CacheDriverFactory::create('database'); + return $this->cache; + } + + public function tearDown() + { + $this->cache->clear(); + parent::tearDown(); + } +} diff --git a/tests/src/Core/Cache/MemcachedCacheDriverTest.php b/tests/src/Core/Cache/MemcachedCacheDriverTest.php new file mode 100644 index 0000000000..ff76ddefc4 --- /dev/null +++ b/tests/src/Core/Cache/MemcachedCacheDriverTest.php @@ -0,0 +1,39 @@ +cache = CacheDriverFactory::create('memcached'); + } catch (\Exception $exception) { + print "Memcached - TestCase failed: " . $exception->getMessage(); + throw new \Exception(); + } + return $this->cache; + } else { + $this->markTestSkipped('Memcached driver isn\'t available'); + return null; + } + } + + public function tearDown() + { + if (class_exists('Memcached')) { + $this->cache->clear(); + } + parent::tearDown(); + } +} diff --git a/tests/src/Core/Cache/RedisCacheDriverTest.php b/tests/src/Core/Cache/RedisCacheDriverTest.php new file mode 100644 index 0000000000..44ff0d42b1 --- /dev/null +++ b/tests/src/Core/Cache/RedisCacheDriverTest.php @@ -0,0 +1,39 @@ +cache = CacheDriverFactory::create('redis'); + } catch (\Exception $exception) { + print "Redis - TestCase failed: " . $exception->getMessage(); + throw new \Exception(); + } + return $this->cache; + } else { + $this->markTestSkipped('Redis driver isn\'t available'); + return null; + } + } + + public function tearDown() + { + if (class_exists('Redis')) { + $this->cache->clear(); + } + parent::tearDown(); + } +} diff --git a/tests/src/Core/Lock/ArrayCacheLockDriverTest.php b/tests/src/Core/Lock/ArrayCacheLockDriverTest.php index 0e58bf49e3..dc044f5c5c 100644 --- a/tests/src/Core/Lock/ArrayCacheLockDriverTest.php +++ b/tests/src/Core/Lock/ArrayCacheLockDriverTest.php @@ -24,4 +24,10 @@ class ArrayCacheLockDriverTest extends LockTest $this->cache->clear(); parent::tearDown(); } + + public function testLockTTL() + { + // ArrayCache doesn't support TTL + return true; + } } diff --git a/tests/src/Core/Lock/LockTest.php b/tests/src/Core/Lock/LockTest.php index a120edeb0c..dafbd74a6f 100644 --- a/tests/src/Core/Lock/LockTest.php +++ b/tests/src/Core/Lock/LockTest.php @@ -86,4 +86,24 @@ abstract class LockTest extends DatabaseTest $this->assertFalse($this->instance->isLocked('bar')); $this->assertFalse($this->instance->isLocked('nice')); } + + function testLockTTL() { + + // TODO [nupplaphil] - Because of the Datetime-Utils for the database, we have to wait a FULL second between the checks to invalidate the db-locks/cache + $this->instance->acquireLock('foo', 1, 1); + $this->instance->acquireLock('bar', 1, 3); + + $this->assertTrue($this->instance->isLocked('foo')); + $this->assertTrue($this->instance->isLocked('bar')); + + sleep(2); + + $this->assertFalse($this->instance->isLocked('foo')); + $this->assertTrue($this->instance->isLocked('bar')); + + sleep(2); + + $this->assertFalse($this->instance->isLocked('foo')); + $this->assertFalse($this->instance->isLocked('bar')); + } } diff --git a/tests/src/Core/Lock/SemaphoreLockDriverTest.php b/tests/src/Core/Lock/SemaphoreLockDriverTest.php index 48c2aff4df..cd4b915733 100644 --- a/tests/src/Core/Lock/SemaphoreLockDriverTest.php +++ b/tests/src/Core/Lock/SemaphoreLockDriverTest.php @@ -23,4 +23,10 @@ class SemaphoreLockDriverTest extends LockTest $this->semaphoreLockDriver->releaseAll(); parent::tearDown(); } + + function testLockTTL() + { + // Semaphore doesn't work with TTL + return true; + } } From 065b83d148775f30712532d0242f7d1508a7d0b0 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Sat, 7 Jul 2018 20:07:07 +0200 Subject: [PATCH 62/65] Fixed memcache & unittests --- .travis.yml | 1 + src/Core/Cache/MemcacheCacheDriver.php | 2 +- .../Core/Cache/MemcacheCacheDriverTest.php | 39 ++++++++++++++++++ .../Core/Lock/MemcacheCacheLockDriverTest.php | 40 +++++++++++++++++++ 4 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 tests/src/Core/Cache/MemcacheCacheDriverTest.php create mode 100644 tests/src/Core/Lock/MemcacheCacheLockDriverTest.php diff --git a/.travis.yml b/.travis.yml index 6e7ac1c2e0..93d1190f23 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,3 +21,4 @@ before_script: - mysql -utravis test < database.sql - echo "extension=redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - echo "extension=memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini + - echo "extension=memcache.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini \ No newline at end of file diff --git a/src/Core/Cache/MemcacheCacheDriver.php b/src/Core/Cache/MemcacheCacheDriver.php index cd12be8ecd..bff543b542 100644 --- a/src/Core/Cache/MemcacheCacheDriver.php +++ b/src/Core/Cache/MemcacheCacheDriver.php @@ -111,6 +111,6 @@ class MemcacheCacheDriver extends AbstractCacheDriver implements IMemoryCacheDri public function add($key, $value, $ttl = Cache::FIVE_MINUTES) { $cachekey = $this->getCacheKey($key); - return $this->memcache->add($cachekey, $value, $ttl); + return $this->memcache->add($cachekey, serialize($value), MEMCACHE_COMPRESSED, $ttl); } } diff --git a/tests/src/Core/Cache/MemcacheCacheDriverTest.php b/tests/src/Core/Cache/MemcacheCacheDriverTest.php new file mode 100644 index 0000000000..4dbd10289e --- /dev/null +++ b/tests/src/Core/Cache/MemcacheCacheDriverTest.php @@ -0,0 +1,39 @@ +cache = CacheDriverFactory::create('memcache'); + } catch (\Exception $exception) { + print "Memcache - TestCase failed: " . $exception->getMessage(); + throw new \Exception(); + } + return $this->cache; + } else { + $this->markTestSkipped('Memcache driver isn\'t available'); + return null; + } + } + + public function tearDown() + { + if (class_exists('Memcache')) { + $this->cache->clear(); + } + parent::tearDown(); + } +} diff --git a/tests/src/Core/Lock/MemcacheCacheLockDriverTest.php b/tests/src/Core/Lock/MemcacheCacheLockDriverTest.php new file mode 100644 index 0000000000..67ccdb57d2 --- /dev/null +++ b/tests/src/Core/Lock/MemcacheCacheLockDriverTest.php @@ -0,0 +1,40 @@ +cache = CacheDriverFactory::create('memcache'); + } catch (\Exception $exception) { + print "Memcache - TestCase failed: " . $exception->getMessage(); + throw new \Exception(); + } + return new CacheLockDriver($this->cache); + } else { + $this->markTestSkipped('Memcache driver isn\'t available'); + return null; + } + } + + public function tearDown() + { + if (class_exists('Memcache')) { + $this->cache->clear(); + } + parent::tearDown(); + } +} From 3cde7a3e4b8f43d3bcb1abf8d6dbe2978027da75 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Sat, 7 Jul 2018 20:35:42 +0200 Subject: [PATCH 63/65] Fixed & added unittests --- tests/src/Core/Cache/ArrayCacheDriverTest.php | 4 +- .../Core/Cache/DatabaseCacheDriverTest.php | 2 +- .../Core/Cache/MemcacheCacheDriverTest.php | 4 +- .../Core/Cache/MemcachedCacheDriverTest.php | 4 +- tests/src/Core/Cache/MemoryCacheTest.php | 92 +++++++++++++++++++ tests/src/Core/Cache/RedisCacheDriverTest.php | 4 +- 6 files changed, 101 insertions(+), 9 deletions(-) create mode 100644 tests/src/Core/Cache/MemoryCacheTest.php diff --git a/tests/src/Core/Cache/ArrayCacheDriverTest.php b/tests/src/Core/Cache/ArrayCacheDriverTest.php index 860e566d88..0cad6e9c7f 100644 --- a/tests/src/Core/Cache/ArrayCacheDriverTest.php +++ b/tests/src/Core/Cache/ArrayCacheDriverTest.php @@ -5,7 +5,7 @@ namespace Friendica\Test\src\Core\Cache; use Friendica\Core\Cache\ArrayCache; -class ArrayCacheDriverTest extends CacheTest +class ArrayCacheDriverTest extends MemoryCacheTest { /** * @var \Friendica\Core\Cache\IMemoryCacheDriver @@ -20,7 +20,7 @@ class ArrayCacheDriverTest extends CacheTest public function tearDown() { - $this->cache->clear(); + $this->cache->clear(false); parent::tearDown(); } diff --git a/tests/src/Core/Cache/DatabaseCacheDriverTest.php b/tests/src/Core/Cache/DatabaseCacheDriverTest.php index ed2e47fb47..5df00fc913 100644 --- a/tests/src/Core/Cache/DatabaseCacheDriverTest.php +++ b/tests/src/Core/Cache/DatabaseCacheDriverTest.php @@ -19,7 +19,7 @@ class DatabaseCacheDriverTest extends CacheTest public function tearDown() { - $this->cache->clear(); + $this->cache->clear(false); parent::tearDown(); } } diff --git a/tests/src/Core/Cache/MemcacheCacheDriverTest.php b/tests/src/Core/Cache/MemcacheCacheDriverTest.php index 4dbd10289e..d2078236e2 100644 --- a/tests/src/Core/Cache/MemcacheCacheDriverTest.php +++ b/tests/src/Core/Cache/MemcacheCacheDriverTest.php @@ -6,7 +6,7 @@ namespace Friendica\Test\src\Core\Cache; use Friendica\Core\Cache\CacheDriverFactory; -class MemcachedCacheDriverTest extends CacheTest +class MemcacheCacheDriverTest extends MemoryCacheTest { /** * @var \Friendica\Core\Cache\IMemoryCacheDriver @@ -32,7 +32,7 @@ class MemcachedCacheDriverTest extends CacheTest public function tearDown() { if (class_exists('Memcache')) { - $this->cache->clear(); + $this->cache->clear(false); } parent::tearDown(); } diff --git a/tests/src/Core/Cache/MemcachedCacheDriverTest.php b/tests/src/Core/Cache/MemcachedCacheDriverTest.php index ff76ddefc4..2484517424 100644 --- a/tests/src/Core/Cache/MemcachedCacheDriverTest.php +++ b/tests/src/Core/Cache/MemcachedCacheDriverTest.php @@ -6,7 +6,7 @@ namespace Friendica\Test\src\Core\Cache; use Friendica\Core\Cache\CacheDriverFactory; -class MemcachedCacheDriverTest extends CacheTest +class MemcachedCacheDriverTest extends MemoryCacheTest { /** * @var \Friendica\Core\Cache\IMemoryCacheDriver @@ -32,7 +32,7 @@ class MemcachedCacheDriverTest extends CacheTest public function tearDown() { if (class_exists('Memcached')) { - $this->cache->clear(); + $this->cache->clear(false); } parent::tearDown(); } diff --git a/tests/src/Core/Cache/MemoryCacheTest.php b/tests/src/Core/Cache/MemoryCacheTest.php new file mode 100644 index 0000000000..3f7af71f6d --- /dev/null +++ b/tests/src/Core/Cache/MemoryCacheTest.php @@ -0,0 +1,92 @@ +instance instanceof IMemoryCacheDriver)) { + throw new \Exception('MemoryCacheTest unsupported'); + } + } + + function testCompareSet() { + $this->assertNull($this->instance->get('value1')); + + $value='foobar'; + $this->instance->add('value1', $value); + $received=$this->instance->get('value1'); + $this->assertEquals($value, $received, 'Value received from cache not equal to the original'); + $newValue='ipsum lorum'; + $this->instance->compareSet('value1', $value, $newValue); + $received=$this->instance->get('value1'); + $this->assertEquals($newValue, $received, 'Value not overwritten by compareSet'); + } + + function testNegativeCompareSet() { + $this->assertNull($this->instance->get('value1')); + + $value='foobar'; + $this->instance->add('value1', $value); + $received=$this->instance->get('value1'); + $this->assertEquals($value, $received, 'Value received from cache not equal to the original'); + $newValue='ipsum lorum'; + $this->instance->compareSet('value1', 'wrong', $newValue); + $received=$this->instance->get('value1'); + $this->assertNotEquals($newValue, $received, 'Value was wrongly overwritten by compareSet'); + $this->assertEquals($value, $received, 'Value was wrongly overwritten by any other value'); + } + + function testCompareDelete() { + $this->assertNull($this->instance->get('value1')); + + $value='foobar'; + $this->instance->add('value1', $value); + $received=$this->instance->get('value1'); + $this->assertEquals($value, $received, 'Value received from cache not equal to the original'); + $this->instance->compareDelete('value1', $value); + $this->assertNull($this->instance->get('value1'), 'Value was not deleted by compareDelete'); + } + + function testNegativeCompareDelete() { + $this->assertNull($this->instance->get('value1')); + + $value='foobar'; + $this->instance->add('value1', $value); + $received=$this->instance->get('value1'); + $this->assertEquals($value, $received, 'Value received from cache not equal to the original'); + $this->instance->compareDelete('value1', 'wrong'); + $this->assertNotNull($this->instance->get('value1'), 'Value was wrongly compareDeleted'); + + $this->instance->compareDelete('value1', $value); + $this->assertNull($this->instance->get('value1'), 'Value was wrongly NOT deleted by compareDelete'); + } + + function testAdd() { + $this->assertNull($this->instance->get('value1')); + + $value='foobar'; + $this->instance->add('value1', $value); + + $newValue='ipsum lorum'; + $this->instance->add('value1', $newValue); + $received=$this->instance->get('value1'); + $this->assertNotEquals($newValue, $received, 'Value was wrongly overwritten by add'); + $this->assertEquals($value, $received, 'Value was wrongly overwritten by any other value'); + + $this->instance->delete('value1'); + $this->instance->add('value1', $newValue); + $received=$this->instance->get('value1'); + $this->assertEquals($newValue, $received, 'Value was not overwritten by add'); + $this->assertNotEquals($value, $received, 'Value was not overwritten by any other value'); + } +} \ No newline at end of file diff --git a/tests/src/Core/Cache/RedisCacheDriverTest.php b/tests/src/Core/Cache/RedisCacheDriverTest.php index 44ff0d42b1..e13d95df4d 100644 --- a/tests/src/Core/Cache/RedisCacheDriverTest.php +++ b/tests/src/Core/Cache/RedisCacheDriverTest.php @@ -6,7 +6,7 @@ namespace Friendica\Test\src\Core\Cache; use Friendica\Core\Cache\CacheDriverFactory; -class RedisCacheDriverTest extends CacheTest +class RedisCacheDriverTest extends MemoryCacheTest { /** * @var \Friendica\Core\Cache\IMemoryCacheDriver @@ -32,7 +32,7 @@ class RedisCacheDriverTest extends CacheTest public function tearDown() { if (class_exists('Redis')) { - $this->cache->clear(); + $this->cache->clear(false); } parent::tearDown(); } From 1e96faca4c9825bf6a8d8a50dc37498b764b9a3d Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Sat, 7 Jul 2018 20:42:44 +0200 Subject: [PATCH 64/65] removed memcache unit-test because lack of support in travis --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 93d1190f23..6e7ac1c2e0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,4 +21,3 @@ before_script: - mysql -utravis test < database.sql - echo "extension=redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - echo "extension=memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - - echo "extension=memcache.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini \ No newline at end of file From ff24d0d567441b563f88f19374150ae8b4d264c1 Mon Sep 17 00:00:00 2001 From: Philipp Holzer Date: Sat, 7 Jul 2018 20:51:08 +0200 Subject: [PATCH 65/65] code-standards wrap operators with spaces --- tests/src/Core/Cache/CacheTest.php | 19 ++++++------- tests/src/Core/Cache/MemoryCacheTest.php | 34 +++++++++++++----------- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/tests/src/Core/Cache/CacheTest.php b/tests/src/Core/Cache/CacheTest.php index 419e0cd2bd..4f3e4d351c 100644 --- a/tests/src/Core/Cache/CacheTest.php +++ b/tests/src/Core/Cache/CacheTest.php @@ -36,18 +36,19 @@ abstract class CacheTest extends DatabaseTest function testSimple() { $this->assertNull($this->instance->get('value1')); - $value='foobar'; + $value = 'foobar'; $this->instance->set('value1', $value); - $received=$this->instance->get('value1'); + $received = $this->instance->get('value1'); $this->assertEquals($value, $received, 'Value received from cache not equal to the original'); - $value='ipsum lorum'; + + $value = 'ipsum lorum'; $this->instance->set('value1', $value); - $received=$this->instance->get('value1'); + $received = $this->instance->get('value1'); $this->assertEquals($value, $received, 'Value not overwritten by second set'); - $value2='foobar'; + $value2 = 'foobar'; $this->instance->set('value2', $value2); - $received2=$this->instance->get('value2'); + $received2 = $this->instance->get('value2'); $this->assertEquals($value, $received, 'Value changed while setting other variable'); $this->assertEquals($value2, $received2, 'Second value not equal to original'); @@ -58,7 +59,7 @@ abstract class CacheTest extends DatabaseTest } function testClear() { - $value='ipsum lorum'; + $value = 'ipsum lorum'; $this->instance->set('1_value1', $value . '1'); $this->instance->set('1_value2', $value . '2'); $this->instance->set('2_value1', $value . '3'); @@ -94,9 +95,9 @@ abstract class CacheTest extends DatabaseTest function testTTL() { $this->assertNull($this->instance->get('value1')); - $value='foobar'; + $value = 'foobar'; $this->instance->set('value1', $value, 1); - $received=$this->instance->get('value1'); + $received = $this->instance->get('value1'); $this->assertEquals($value, $received, 'Value received from cache not equal to the original'); sleep(2); diff --git a/tests/src/Core/Cache/MemoryCacheTest.php b/tests/src/Core/Cache/MemoryCacheTest.php index 3f7af71f6d..670df2fe18 100644 --- a/tests/src/Core/Cache/MemoryCacheTest.php +++ b/tests/src/Core/Cache/MemoryCacheTest.php @@ -22,26 +22,28 @@ abstract class MemoryCacheTest extends CacheTest function testCompareSet() { $this->assertNull($this->instance->get('value1')); - $value='foobar'; + $value = 'foobar'; $this->instance->add('value1', $value); - $received=$this->instance->get('value1'); + $received = $this->instance->get('value1'); $this->assertEquals($value, $received, 'Value received from cache not equal to the original'); - $newValue='ipsum lorum'; + + $newValue = 'ipsum lorum'; $this->instance->compareSet('value1', $value, $newValue); - $received=$this->instance->get('value1'); + $received = $this->instance->get('value1'); $this->assertEquals($newValue, $received, 'Value not overwritten by compareSet'); } function testNegativeCompareSet() { $this->assertNull($this->instance->get('value1')); - $value='foobar'; + $value = 'foobar'; $this->instance->add('value1', $value); - $received=$this->instance->get('value1'); + $received = $this->instance->get('value1'); $this->assertEquals($value, $received, 'Value received from cache not equal to the original'); - $newValue='ipsum lorum'; + + $newValue = 'ipsum lorum'; $this->instance->compareSet('value1', 'wrong', $newValue); - $received=$this->instance->get('value1'); + $received = $this->instance->get('value1'); $this->assertNotEquals($newValue, $received, 'Value was wrongly overwritten by compareSet'); $this->assertEquals($value, $received, 'Value was wrongly overwritten by any other value'); } @@ -49,9 +51,9 @@ abstract class MemoryCacheTest extends CacheTest function testCompareDelete() { $this->assertNull($this->instance->get('value1')); - $value='foobar'; + $value = 'foobar'; $this->instance->add('value1', $value); - $received=$this->instance->get('value1'); + $received = $this->instance->get('value1'); $this->assertEquals($value, $received, 'Value received from cache not equal to the original'); $this->instance->compareDelete('value1', $value); $this->assertNull($this->instance->get('value1'), 'Value was not deleted by compareDelete'); @@ -60,9 +62,9 @@ abstract class MemoryCacheTest extends CacheTest function testNegativeCompareDelete() { $this->assertNull($this->instance->get('value1')); - $value='foobar'; + $value = 'foobar'; $this->instance->add('value1', $value); - $received=$this->instance->get('value1'); + $received = $this->instance->get('value1'); $this->assertEquals($value, $received, 'Value received from cache not equal to the original'); $this->instance->compareDelete('value1', 'wrong'); $this->assertNotNull($this->instance->get('value1'), 'Value was wrongly compareDeleted'); @@ -74,18 +76,18 @@ abstract class MemoryCacheTest extends CacheTest function testAdd() { $this->assertNull($this->instance->get('value1')); - $value='foobar'; + $value = 'foobar'; $this->instance->add('value1', $value); - $newValue='ipsum lorum'; + $newValue = 'ipsum lorum'; $this->instance->add('value1', $newValue); - $received=$this->instance->get('value1'); + $received = $this->instance->get('value1'); $this->assertNotEquals($newValue, $received, 'Value was wrongly overwritten by add'); $this->assertEquals($value, $received, 'Value was wrongly overwritten by any other value'); $this->instance->delete('value1'); $this->instance->add('value1', $newValue); - $received=$this->instance->get('value1'); + $received = $this->instance->get('value1'); $this->assertEquals($newValue, $received, 'Value was not overwritten by add'); $this->assertNotEquals($value, $received, 'Value was not overwritten by any other value'); }