diff --git a/src/application/controller/api/user/avatar.php b/src/application/controller/api/user/avatar.php
index 04ef82f..759aaeb 100644
--- a/src/application/controller/api/user/avatar.php
+++ b/src/application/controller/api/user/avatar.php
@@ -1,88 +1,113 @@
false,
'message' => _('Internal server error'),
'avatar' => false
];
+// Access allowed for authorized users only
if (isset($_SESSION['userName'])) {
+ // Prepare user request, authorized user by default
$userName = isset($_GET['userName']) ? Filter::userName($_GET['userName']) : $_SESSION['userName'];
- if ($avatar = $_memcache->get('api.user.avatar.' . $userName)) {
+ // Check user exists in the database
+ if ($userId = $_modelUser->getUserId($userName)) {
- $response = [
- 'success' => true,
- 'message' => _('Avatar successfully received from Cache'),
- 'avatar' => $avatar
- ];
+ /*
+ * Step 1: try to obtain avatar from cache
+ *
+ * */
+ if ($mcAvatar = $_memcache->get('api.user.avatar.' . $userName)) {
- } else if ($avatarVersions = $_twister->getDHT($userName, 'avatar', 's')) {
+ $response = [
+ 'success' => true,
+ 'message' => _('Avatar successfully received from Cache'),
+ 'avatar' => $mcAvatar
+ ];
- // Check avatar exists
- if ($userId = $_modelUser->getUserId($userName)) {
+ /*
+ * Step 2: try to obtain profile from DHT
+ *
+ * */
+ } else if ($dhtAvatarRevisions = $_twister->getDHTAvatarRevisions($userName)) {
// Add DHT version if not exists
- foreach ($avatarVersions as $avatarVersion) {
+ foreach ((array) $dhtAvatarRevisions as $dhtAvatarRevision) {
if (!$_modelAvatar->versionExists($userId,
- Filter::int($avatarVersion['p']['height']),
- Filter::int($avatarVersion['p']['seq']))) {
-
- $_modelAvatar->add( $userId,
- Filter::int($avatarVersion['p']['height']),
- Filter::int($avatarVersion['p']['seq']),
- Filter::int($avatarVersion['p']['time']),
- Filter::string($avatarVersion['p']['v']));
+ $dhtAvatarRevision['height'],
+ $dhtAvatarRevision['seq'])) {
+
+ $_modelAvatar->add($userId,
+ $dhtAvatarRevision['height'],
+ $dhtAvatarRevision['seq'],
+ $dhtAvatarRevision['time'],
+ $dhtAvatarRevision['data']);
}
}
}
- // Get latest version available
- if ($avatarInfo = $_modelAvatar->get($userId)) {
+ /*
+ * Step 3: Select latest version available from DB revisions
+ *
+ * */
+ $dbAvatarRevision = $_modelAvatar->get($userId);
+ if ($dbAvatarRevision && Valid::base64image($dbAvatarRevision['data'])) {
+
+ // Response
$response = [
'success' => true,
- 'message' => _('Avatar successfully received from DHT'),
- 'avatar' => $avatarInfo['data']
+ 'message' => _('Avatar successfully received from DHT/DB'),
+ 'avatar' => $dbAvatarRevision['data'] // format
];
- $_memcache->set('api.user.avatar.' . $userName, $avatarInfo['data'], MEMCACHE_COMPRESS, MEMCACHE_DHT_AVATAR_TIMEOUT);
+ // Save request into the cache pool
+ $_memcache->set('api.user.avatar.' . $userName, $dbAvatarRevision['data'], MEMCACHE_COMPRESS, MEMCACHE_DHT_AVATAR_TIMEOUT);
+ // Cache, DHT, DB not contain any the avatar details about user requested,
+ // Generate and return identity icon
} else {
- $response = [
- 'success' => false,
- 'message' => _('Avatar data not available'),
- 'avatar' => false
- ];
- }
+ // Generate identity icon
+ $fileName = md5($userName);
+ $filePath = PROJECT_DIR . '/cache/image/' . $fileName . '.jpeg';
- // Generate identity icon
- } else {
+ // Identity icons supports file cache
+ if (!file_exists($filePath)) {
+
+ $icon = new Icon();
+ $image = $icon->generateImageResource($fileName, 42, 42, false);
- $fileName = md5($userName);
- $filePath = PROJECT_DIR . '/cache/image/' . $fileName . '.jpeg';
+ file_put_contents($filePath, $image);
+ }
- if (!file_exists($filePath)) {
+ $identityIcon = 'data:image/jpeg;base64,' . base64_encode(file_get_contents($filePath));
- $icon = new Icon();
- $image = $icon->generateImageResource($fileName, 42, 42, false);
+ $response = [
+ 'success' => true,
+ 'message' => _('Could not receive any avatar details, generated identity icon'),
+ 'avatar' => $identityIcon
+ ];
- file_put_contents($filePath, $image);
+ // Save identity icon into the cache pool
+ $_memcache->set('api.user.avatar.' . $userName, $identityIcon, MEMCACHE_COMPRESS, MEMCACHE_DHT_AVATAR_TIMEOUT);
}
- $image = file_get_contents($filePath);
+ // User not found in the local database registry
+ } else {
$response = [
- 'success' => true,
- 'message' => _('Avatar successfully received from Identity'),
- 'avatar' => 'data:image/jpeg;base64,' . base64_encode($image)
+ 'success' => false,
+ 'message' => _('Requested user not found'),
+ 'profile' => []
];
-
}
+// Session expired response
} else {
$response = [
diff --git a/src/application/controller/api/user/profile.php b/src/application/controller/api/user/profile.php
index 483b1e9..20901c6 100644
--- a/src/application/controller/api/user/profile.php
+++ b/src/application/controller/api/user/profile.php
@@ -1,92 +1,110 @@
false,
'message' => _('Internal server error'),
'profile' => []
];
+// Access allowed for authorized users only
if (isset($_SESSION['userName'])) {
+ // Prepare user request, authorized user by default
$userName = isset($_GET['userName']) ? Filter::userName($_GET['userName']) : $_SESSION['userName'];
- if ($profile = $_memcache->get('api.user.profile.' . $userName)) {
+ // Check user exists in the database
+ if ($userId = $_modelUser->getUserId($userName)) {
- $response = [
- 'success' => true,
- 'message' => _('Profile successfully received from Cache'),
- 'profile' => $profile
- ];
+ /*
+ * Step 1: try to obtain profile from cache
+ *
+ * */
+ if ($mcProfile = $_memcache->get('api.user.profile.' . $userName)) {
- } else if ($userProfileVersions = $_twister->getDHT($userName, 'profile', 's')) {
+ $response = [
+ 'success' => true,
+ 'message' => _('Profile successfully received from Cache'),
+ 'profile' => $mcProfile
+ ];
- // Check user exists
- if ($userId = $_modelUser->getUserId($userName)) {
+ /*
+ * Step 2: try to obtain profile from DHT
+ *
+ * */
+ } else if ($dhtProfileRevisions = $_twister->getDHTProfileRevisions($userName)) {
// Add DHT version if not exists
- foreach ($userProfileVersions as $userProfileVersion) {
+ foreach ((array) $dhtProfileRevisions as $dhtProfileRevision) {
+ // Save revision into the database if not exists
if (!$_modelProfile->versionExists($userId,
- Filter::int($userProfileVersion['p']['height']),
- Filter::int($userProfileVersion['p']['seq']))) {
-
- $profile = $userProfileVersion['p']['v'];
+ $dhtProfileRevision['height'],
+ $dhtProfileRevision['seq'])) {
$_modelProfile->add($userId,
- Filter::int($userProfileVersion['p']['height']),
- Filter::int($userProfileVersion['p']['seq']),
- Filter::int($userProfileVersion['p']['time']),
-
- isset($profile['fullname']) ? Filter::string($profile['fullname']) : '',
- isset($profile['bio']) ? Filter::string($profile['bio']) : '',
- isset($profile['location']) ? Filter::string($profile['location']) : '',
- isset($profile['url']) ? Filter::string($profile['url']) : '',
- isset($profile['bitmessage']) ? Filter::string($profile['bitmessage']) : '',
- isset($profile['tox']) ? Filter::string($profile['tox']) : '');
+ $dhtProfileRevision['height'],
+ $dhtProfileRevision['seq'],
+ $dhtProfileRevision['time'],
+
+ $dhtProfileRevision['fullName'],
+ $dhtProfileRevision['bio'],
+ $dhtProfileRevision['location'],
+ $dhtProfileRevision['url'],
+ $dhtProfileRevision['bitMessage'],
+ $dhtProfileRevision['tox']);
}
}
}
- // Get latest version available
- if ($profileInfo = $_modelProfile->get($userId)) {
+ /*
+ * Step 3: Select latest version available from DB revisions
+ *
+ * */
+ if ($dbProfileRevision = $_modelProfile->get($userId)) {
+ // Format output
$profile = [
'userName' => $userName,
- 'fullName' => Filter::string($profileInfo['fullName']),
- 'location' => Filter::string($profileInfo['location']),
- 'url' => Filter::string($profileInfo['url']),
- 'bitMessage' => Filter::string($profileInfo['bitMessage']),
- 'tox' => Filter::string($profileInfo['tox']),
- 'bio' => nl2br(Filter::string($profileInfo['bio'])),
+ 'fullName' => Format::text($dbProfileRevision['fullName']),
+ 'location' => Format::text($dbProfileRevision['location']),
+ 'url' => Format::text($dbProfileRevision['url']),
+ 'bitMessage' => Format::text($dbProfileRevision['bitMessage']),
+ 'tox' => Format::text($dbProfileRevision['tox']),
+ 'bio' => Format::text($dbProfileRevision['bio']),
];
+ // Save request into the cache pool
+ $_memcache->set('api.user.profile.' . $userName, $profile, MEMCACHE_COMPRESS, MEMCACHE_DHT_PROFILE_TIMEOUT);
+
+ // Response
$response = [
'success' => true,
- 'message' => _('Profile successfully received from DHT'),
+ 'message' => _('Profile successfully received from DHT/DB'),
'profile' => $profile
];
- $_memcache->set('api.user.profile.' . $userName, $profile, MEMCACHE_COMPRESS, MEMCACHE_DHT_PROFILE_TIMEOUT);
-
+ // Cache, DHT, DB not contain any the details about user requested
} else {
$response = [
'success' => false,
- 'message' => _('Profile data not available'),
+ 'message' => _('Could not receive any profile details'),
'profile' => []
];
}
+ // User not found in the local database registry
} else {
$response = [
'success' => false,
- 'message' => _('Could not receive profile details'),
+ 'message' => _('Requested user not found'),
'profile' => []
];
-
}
+// Session expired response
} else {
$response = [
diff --git a/src/system/helper/filter.php b/src/system/helper/filter.php
index a2fedaf..32345c5 100644
--- a/src/system/helper/filter.php
+++ b/src/system/helper/filter.php
@@ -19,7 +19,7 @@ class Filter {
public static function string(mixed $string) {
- return htmlentities($string, ENT_QUOTES, 'UTF-8');
+ return (string) $string;
}
public static function int(mixed $int) {
diff --git a/src/system/helper/format.php b/src/system/helper/format.php
index f3c0230..57c372e 100644
--- a/src/system/helper/format.php
+++ b/src/system/helper/format.php
@@ -40,24 +40,26 @@ class Format {
} else {
return sprintf(_('%s %s later'), $r, self::plural($r, $v));
}
-
-
}
}
}
- public static function post(string $text) {
+ public static function text(string $string) {
+
+ $string = html_entity_decode($string, ENT_QUOTES, 'UTF-8');
+ $string = htmlentities($string, ENT_QUOTES, 'UTF-8');
+
+ $string = preg_replace("|\*([\S]+)\*|i", "$1", $string);
+ $string = preg_replace("|\~([\S]+)\~|i", "$1", $string);
+ $string = preg_replace("|\_([\S]+)\_|i", "$1", $string);
+ $string = preg_replace("|\-([\S]+)\-|i", "$1", $string);
+ $string = preg_replace("|\`([\S]+)\`|i", "$1", $string);
- $text = preg_replace("|\*([\S]+)\*|i", "$1", $text);
- $text = preg_replace("|\~([\S]+)\~|i", "$1", $text);
- $text = preg_replace("|\_([\S]+)\_|i", "$1", $text);
- $text = preg_replace("|\-([\S]+)\-|i", "$1", $text);
- $text = preg_replace("|\`([\S]+)\`|i", "$1", $text);
+ $string = preg_replace("|@([a-zA-Z0-9_]+)|i", "@$1", $string);
+ $string = preg_replace("|((https?://)+([\d\w\.-]+\.[\w\.]{2,6})[^\s\]\[\<\>]*/?)|i", "$3", $string);
- $text = preg_replace("|@([a-zA-Z0-9_]+)|i", "@$1", $text);
- $text = preg_replace("|((https?://)+([\d\w\.-]+\.[\w\.]{2,6})[^\s\]\[\<\>]*/?)|i", "$3", $text);
- $text = nl2br($text);
+ $string = nl2br($string);
- return $text;
+ return $string;
}
}
\ No newline at end of file
diff --git a/src/system/helper/valid.php b/src/system/helper/valid.php
index 7686808..e7ad6d7 100644
--- a/src/system/helper/valid.php
+++ b/src/system/helper/valid.php
@@ -17,6 +17,38 @@ class Valid {
}
}
+ public static function base64(string $string) {
+
+ if (base64_encode(base64_decode($string, true)) === $string) {
+
+ return true;
+
+ } else {
+
+ return false;
+ }
+ }
+
+ public static function base64image(string $string) {
+
+ $string = str_replace([
+ 'data:image/jpeg;base64,',
+ 'data:image/jpg;base64,',
+ 'data:image/gif;base64,',
+ 'data:image/png;base64,',
+ 'data:image/webp;base64,',
+ ], '', $string);
+
+ if (self::base64($string) && imagecreatefromstring(base64_decode($string))) {
+
+ return true;
+
+ } else {
+
+ return false;
+ }
+ }
+
public static function userName(string $userName) {
if (preg_match('/[^a-zA-Z0-9_]+/u', $userName)) {
diff --git a/src/system/twister.php b/src/system/twister.php
index cd3844e..8286458 100644
--- a/src/system/twister.php
+++ b/src/system/twister.php
@@ -243,6 +243,115 @@ class Twister {
return false;
}
+ public function getDHTProfileRevisions(string $userName) {
+
+ $this->_curl->prepare(
+ '/',
+ 'POST',
+ 30,
+ [
+ 'jsonrpc' => '2.0',
+ 'method' => 'dhtget',
+ 'params' => [
+ $userName,
+ 'profile',
+ 's'
+ ],
+ 'id' => time() + rand()
+ ]
+ );
+
+ if ($response = $this->_curl->execute()) {
+
+ if ($response['error']) {
+
+ $this->_error = _($response['error']['message']);
+
+ } else {
+
+ $dhtProfileVersions = [];
+ foreach ((array) $response['result'] as $dhtProfileVersion) {
+
+ // Required fields validation needed to make the DB revision compare
+ if (isset($dhtProfileVersion['p']['height']) &&
+ isset($dhtProfileVersion['p']['seq']) &&
+ isset($dhtProfileVersion['p']['time'])) {
+
+ // Format revision response
+ $dhtProfileVersions[] = [
+ 'height' => (int) $dhtProfileVersion['p']['height'],
+ 'seq' => (int) $dhtProfileVersion['p']['seq'],
+ 'time' => (int) $dhtProfileVersion['p']['time'],
+
+ 'fullName' => isset($dhtProfileVersion['p']['v']['fullname']) ? (string) $dhtProfileVersion['p']['v']['fullname'] : '',
+ 'bio' => isset($dhtProfileVersion['p']['v']['bio']) ? (string) $dhtProfileVersion['p']['v']['bio'] : '',
+ 'location' => isset($dhtProfileVersion['p']['v']['location']) ? (string) $dhtProfileVersion['p']['v']['location'] : '',
+ 'url' => isset($dhtProfileVersion['p']['v']['url']) ? (string) $dhtProfileVersion['p']['v']['url'] : '',
+ 'bitMessage' => isset($dhtProfileVersion['p']['v']['bitmessage']) ? (string) $dhtProfileVersion['p']['v']['bitmessage'] : '',
+ 'tox' => isset($dhtProfileVersion['p']['v']['tox']) ? (string) $dhtProfileVersion['p']['v']['tox'] : '',
+ ];
+ }
+ }
+
+ return $dhtProfileVersions; // Formatted array
+ }
+ }
+
+ return [];
+ }
+
+ public function getDHTAvatarRevisions(string $userName) {
+
+ $this->_curl->prepare(
+ '/',
+ 'POST',
+ 30,
+ [
+ 'jsonrpc' => '2.0',
+ 'method' => 'dhtget',
+ 'params' => [
+ $userName,
+ 'avatar',
+ 's'
+ ],
+ 'id' => time() + rand()
+ ]
+ );
+
+ if ($response = $this->_curl->execute()) {
+
+ if ($response['error']) {
+
+ $this->_error = _($response['error']['message']);
+
+ } else {
+
+ $dhtAvatarVersions = [];
+ foreach ((array) $response['result'] as $dhtAvatarVersion) {
+
+ // Required fields validation needed to make the DB revision compare
+ if (isset($dhtAvatarVersion['p']['height']) &&
+ isset($dhtAvatarVersion['p']['seq']) &&
+ isset($dhtAvatarVersion['p']['time'])) {
+
+ // Format revision response
+ $dhtAvatarVersions[] = [
+ 'height' => (int) $dhtAvatarVersion['p']['height'],
+ 'seq' => (int) $dhtAvatarVersion['p']['seq'],
+ 'time' => (int) $dhtAvatarVersion['p']['time'],
+
+ 'data' => isset($dhtAvatarVersion['p']['v']) ? (string) $dhtAvatarVersion['p']['v'] : '',
+ ];
+ }
+ }
+
+ return $dhtAvatarVersions; // Formatted array
+ }
+ }
+
+ return [];
+ }
+
public function getDHT(string $userName, string $command, string $flag) {
$this->_curl->prepare(