From 3a23117ebfcfaf6fddfda82f73789df89e2e6adf Mon Sep 17 00:00:00 2001 From: El RIDO Date: Wed, 19 Nov 2025 09:36:08 +0100 Subject: [PATCH] Refactored translation of exception messages --- CHANGELOG.md | 4 +- composer.lock | 24 ++++----- lib/Configuration.php | 2 +- lib/Controller.php | 28 +++++------ lib/Data/Database.php | 55 ++++++++++++++------- lib/Data/Filesystem.php | 20 ++++---- lib/Data/GoogleCloudStorage.php | 8 ++- lib/Data/S3Storage.php | 11 +++-- lib/Exception/JsonException.php | 37 ++++++++++++++ lib/{ => Exception}/TranslatedException.php | 2 +- lib/I18n.php | 2 + lib/Json.php | 21 +++----- lib/Model/AbstractModel.php | 2 +- lib/Model/Comment.php | 2 +- lib/Model/Paste.php | 2 +- lib/Persistence/TrafficLimiter.php | 2 +- lib/Proxy/AbstractProxy.php | 4 +- lib/Proxy/ShlinkProxy.php | 18 ++++--- lib/Request.php | 4 +- tpl/bootstrap.php | 19 ++++--- tpl/bootstrap5.php | 19 ++++--- vendor/composer/autoload_classmap.php | 3 +- vendor/composer/autoload_static.php | 3 +- vendor/composer/installed.php | 4 +- 24 files changed, 186 insertions(+), 110 deletions(-) create mode 100644 lib/Exception/JsonException.php rename lib/{ => Exception}/TranslatedException.php (96%) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7977c0d..8002155b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,9 @@ # PrivateBin version history ## 2.0.4 (not yet released) -* CHANGED: Deduplicate JSON error message translations. +* CHANGED: Deduplicate JSON error message translations +* CHANGED: Refactored translation of exception messages +* FIXED: Some exceptions not getting translated ## 1.7.9 (2025-11-13) * CHANGED: Upgrading libraries to: base-x 5.0.1, bootstrap 5.3.8, DOMpurify 3.2.7, ip-lib 1.21.0 & kjua 0.10.0 diff --git a/composer.lock b/composer.lock index dac377f9..a7a66ba0 100644 --- a/composer.lock +++ b/composer.lock @@ -397,16 +397,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.6.1", + "version": "v5.6.2", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2" + "reference": "3a454ca033b9e06b63282ce19562e892747449bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", - "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb", + "reference": "3a454ca033b9e06b63282ce19562e892747449bb", "shasum": "" }, "require": { @@ -449,9 +449,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2" }, - "time": "2025-08-13T20:13:15+00:00" + "time": "2025-10-21T19:32:17+00:00" }, { "name": "phar-io/manifest", @@ -2014,16 +2014,16 @@ }, { "name": "theseer/tokenizer", - "version": "1.2.3", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + "reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/d74205c497bfbca49f34d4bc4c19c17e22db4ebb", + "reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb", "shasum": "" }, "require": { @@ -2052,7 +2052,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.3" + "source": "https://github.com/theseer/tokenizer/tree/1.3.0" }, "funding": [ { @@ -2060,7 +2060,7 @@ "type": "github" } ], - "time": "2024-03-03T12:36:25+00:00" + "time": "2025-11-13T13:44:09+00:00" } ], "aliases": [], diff --git a/lib/Configuration.php b/lib/Configuration.php index c4651f8b..7836c3ec 100644 --- a/lib/Configuration.php +++ b/lib/Configuration.php @@ -12,7 +12,7 @@ namespace PrivateBin; use Exception; -use PrivateBin\TranslatedException; +use PrivateBin\Exception\TranslatedException; /** * Configuration diff --git a/lib/Controller.php b/lib/Controller.php index 2e056db6..056647de 100644 --- a/lib/Controller.php +++ b/lib/Controller.php @@ -12,12 +12,13 @@ namespace PrivateBin; use Exception; +use PrivateBin\Exception\JsonException; +use PrivateBin\Exception\TranslatedException; use PrivateBin\Persistence\ServerSalt; use PrivateBin\Persistence\TrafficLimiter; use PrivateBin\Proxy\AbstractProxy; use PrivateBin\Proxy\ShlinkProxy; use PrivateBin\Proxy\YourlsProxy; -use PrivateBin\TranslatedException; /** * Controller @@ -308,11 +309,10 @@ class Controller $comment = $paste->getComment($data['parentid']); $comment->setData($data); $comment->store(); - } catch (TranslatedException $e) { + $this->_json_result($comment->getId()); + } catch (Exception $e) { $this->_json_error($e->getMessage()); - return; } - $this->_json_result($comment->getId()); } else { $this->_json_error(I18n::_('Invalid data.')); } @@ -321,21 +321,13 @@ class Controller else { try { $this->_model->purge(); - } catch (Exception $e) { // JSON error!!! - error_log('Error purging documents: ' . $e->getMessage() . PHP_EOL . - 'Use the administration scripts statistics to find ' . - 'damaged paste IDs and either delete them or restore them ' . - 'from backup.'); - } - $paste = $this->_model->getPaste(); - try { + $paste = $this->_model->getPaste(); $paste->setData($data); $paste->store(); - } catch (TranslatedException $e) { + $this->_json_result($paste->getId(), array('deletetoken' => $paste->getDeleteToken())); + } catch (Exception $e) { $this->_json_error($e->getMessage()); - return; } - $this->_json_result($paste->getId(), array('deletetoken' => $paste->getDeleteToken())); } } @@ -365,7 +357,7 @@ class Controller } else { $this->_error = self::GENERIC_ERROR; } - } catch (Exception $e) { + } catch (TranslatedException $e) { $this->_error = $e->getMessage(); } if ($this->_request->isJsonApiCall()) { @@ -470,7 +462,7 @@ class Controller } $page->assign('BASEPATH', I18n::_($this->_conf->getKey('basepath'))); $page->assign('STATUS', I18n::_($this->_status)); - $page->assign('ISDELETED', I18n::_(json_encode($this->_is_deleted))); + $page->assign('ISDELETED', $this->_is_deleted); $page->assign('VERSION', self::VERSION); $page->assign('DISCUSSION', $this->_conf->getKey('discussion')); $page->assign('OPENDISCUSSION', $this->_conf->getKey('opendiscussion')); @@ -546,6 +538,7 @@ class Controller * * @access private * @param string $error + * @throws JsonException */ private function _json_error($error) { @@ -562,6 +555,7 @@ class Controller * @access private * @param string $dataid * @param array $other + * @throws JsonException */ private function _json_result($dataid, $other = array()) { diff --git a/lib/Data/Database.php b/lib/Data/Database.php index 0fd42dcc..108278a5 100644 --- a/lib/Data/Database.php +++ b/lib/Data/Database.php @@ -15,6 +15,7 @@ use Exception; use PDO; use PDOException; use PrivateBin\Controller; +use PrivateBin\Exception\JsonException; use PrivateBin\Json; /** @@ -179,18 +180,24 @@ class Database extends AbstractData 'SELECT * FROM "' . $this->_sanitizeIdentifier('paste') . '" WHERE "dataid" = ?', array($pasteid), true ); - } catch (Exception $e) { + } catch (PDOException $e) { $row = false; } if ($row === false) { return false; } // create array - $paste = Json::decode($row['data']); + try { + $paste = Json::decode($row['data']); + } catch (JsonException $e) { + error_log('Error while reading a paste from the database: ' . $e->getMessage()); + $paste = array(); + } try { $paste['meta'] = Json::decode($row['meta']); - } catch (Exception $e) { + } catch (JsonException $e) { + error_log('Error while reading a paste from the database: ' . $e->getMessage()); $paste['meta'] = array(); } $expire_date = (int) $row['expiredate']; @@ -233,7 +240,7 @@ class Database extends AbstractData 'SELECT "dataid" FROM "' . $this->_sanitizeIdentifier('paste') . '" WHERE "dataid" = ?', array($pasteid), true ); - } catch (Exception $e) { + } catch (PDOException $e) { return false; } return (bool) $row; @@ -253,7 +260,7 @@ class Database extends AbstractData { try { $data = Json::encode($comment); - } catch (Exception $e) { + } catch (JsonException $e) { error_log('Error while attempting to insert a comment into the database: ' . $e->getMessage()); return false; } @@ -274,7 +281,7 @@ class Database extends AbstractData $meta['created'], ) ); - } catch (Exception $e) { + } catch (PDOException $e) { error_log('Error while attempting to insert a comment into the database: ' . $e->getMessage()); return false; } @@ -298,8 +305,14 @@ class Database extends AbstractData $comments = array(); if (count($rows)) { foreach ($rows as $row) { + try { + $data = Json::decode($row['data']); + } catch (JsonException $e) { + error_log('Error while reading a comment from the database: ' . $e->getMessage()); + $data = array(); + } $i = $this->getOpenSlot($comments, (int) $row['postdate']); - $comments[$i] = Json::decode($row['data']); + $comments[$i] = $data; $comments[$i]['id'] = $row['dataid']; $comments[$i]['parentid'] = $row['parentid']; $comments[$i]['meta'] = array('created' => (int) $row['postdate']); @@ -329,7 +342,7 @@ class Database extends AbstractData '" WHERE "pasteid" = ? AND "parentid" = ? AND "dataid" = ?', array($pasteid, $parentid, $commentid), true ); - } catch (Exception $e) { + } catch (PDOException $e) { return false; } } @@ -349,7 +362,8 @@ class Database extends AbstractData $this->_last_cache[$key] = $value; try { $value = Json::encode($this->_last_cache); - } catch (Exception $e) { + } catch (JsonException $e) { + error_log('Error encoding JSON for table "config", row "traffic_limiter": ' . $e->getMessage()); return false; } } @@ -393,7 +407,8 @@ class Database extends AbstractData if ($value && $namespace === 'traffic_limiter') { try { $this->_last_cache = Json::decode($value); - } catch (Exception $e) { + } catch (JsonException $e) { + error_log('Error decoding JSON from table "config", row "traffic_limiter": ' . $e->getMessage()); $this->_last_cache = array(); } if (array_key_exists($key, $this->_last_cache)) { @@ -412,13 +427,18 @@ class Database extends AbstractData */ protected function _getExpiredPastes($batchsize) { - $statement = $this->_db->prepare( - 'SELECT "dataid" FROM "' . $this->_sanitizeIdentifier('paste') . - '" WHERE "expiredate" < ? AND "expiredate" != ? ' . - ($this->_type === 'oci' ? 'FETCH NEXT ? ROWS ONLY' : 'LIMIT ?') - ); - $statement->execute(array(time(), 0, $batchsize)); - return $statement->fetchAll(PDO::FETCH_COLUMN, 0); + try { + $statement = $this->_db->prepare( + 'SELECT "dataid" FROM "' . $this->_sanitizeIdentifier('paste') . + '" WHERE "expiredate" < ? AND "expiredate" != ? ' . + ($this->_type === 'oci' ? 'FETCH NEXT ? ROWS ONLY' : 'LIMIT ?') + ); + $statement->execute(array(time(), 0, $batchsize)); + return $statement->fetchAll(PDO::FETCH_COLUMN, 0); + } catch (PDOException $e) { + error_log('Error while attempting to find expired pastes in the database: ' . $e->getMessage()); + return array(); + } } /** @@ -552,6 +572,7 @@ class Database extends AbstractData '" WHERE "id" = ?', array($key), true ); } catch (PDOException $e) { + error_log('Error while attempting to fetch configuration key "' . $key . '" in the database: ' . $e->getMessage()); return ''; } return $row ? $row['value'] : ''; diff --git a/lib/Data/Filesystem.php b/lib/Data/Filesystem.php index e4377a9f..751980ab 100644 --- a/lib/Data/Filesystem.php +++ b/lib/Data/Filesystem.php @@ -11,8 +11,8 @@ namespace PrivateBin\Data; -use Exception; use GlobIterator; +use PrivateBin\Exception\JsonException; use PrivateBin\Json; /** @@ -104,13 +104,10 @@ class Filesystem extends AbstractData */ public function read($pasteid) { - if ( - !$this->exists($pasteid) || - !$paste = $this->_get($this->_dataid2path($pasteid) . $pasteid . '.php') - ) { - return false; + if ($this->exists($pasteid)) { + return $this->_get($this->_dataid2path($pasteid) . $pasteid . '.php'); } - return $paste; + return false; } /** @@ -346,7 +343,12 @@ class Filesystem extends AbstractData file_get_contents($filename), strlen(self::PROTECTION_LINE . PHP_EOL) ); - return Json::decode($data); + try { + return Json::decode($data); + } catch (JsonException $e) { + error_log('Error decoding JSON from "' . $filename . '": ' . $e->getMessage()); + return false; + } } /** @@ -450,7 +452,7 @@ class Filesystem extends AbstractData $filename, self::PROTECTION_LINE . PHP_EOL . Json::encode($data) ); - } catch (Exception $e) { + } catch (JsonException $e) { error_log('Error while trying to store data to the filesystem at path "' . $filename . '": ' . $e->getMessage()); return false; } diff --git a/lib/Data/GoogleCloudStorage.php b/lib/Data/GoogleCloudStorage.php index 9f64abe5..2ebfb7fe 100644 --- a/lib/Data/GoogleCloudStorage.php +++ b/lib/Data/GoogleCloudStorage.php @@ -15,6 +15,7 @@ use Exception; use Google\Cloud\Core\Exception\NotFoundException; use Google\Cloud\Storage\Bucket; use Google\Cloud\Storage\StorageClient; +use PrivateBin\Exception\JsonException; use PrivateBin\Json; class GoogleCloudStorage extends AbstractData @@ -219,7 +220,12 @@ class GoogleCloudStorage extends AbstractData try { foreach ($this->_bucket->objects(array('prefix' => $prefix)) as $key) { $data = $this->_bucket->object($key->name())->downloadAsString(); - $comment = Json::decode($data); + try { + $comment = Json::decode($data); + } catch (JsonException $e) { + error_log('failed to read comment from ' . $key->name() . ', ' . $e->getMessage()); + $comment = array(); + } $comment['id'] = basename($key->name()); $slot = $this->getOpenSlot($comments, (int) $comment['meta']['created']); $comments[$slot] = $comment; diff --git a/lib/Data/S3Storage.php b/lib/Data/S3Storage.php index 526a9ec2..575f90f4 100644 --- a/lib/Data/S3Storage.php +++ b/lib/Data/S3Storage.php @@ -37,6 +37,7 @@ namespace PrivateBin\Data; use Aws\S3\Exception\S3Exception; use Aws\S3\S3Client; +use PrivateBin\Exception\JsonException; use PrivateBin\Json; class S3Storage extends AbstractData @@ -177,12 +178,14 @@ class S3Storage extends AbstractData 'ContentType' => 'application/json', 'Metadata' => $metadata, )); + return true; } catch (S3Exception $e) { error_log('failed to upload ' . $key . ' to ' . $this->_bucket . ', ' . trim(preg_replace('/\s\s+/', ' ', $e->getMessage()))); - return false; + } catch (JsonException $e) { + error_log('failed to JSON encode ' . $key . ', ' . $e->getMessage()); } - return true; + return false; } /** @@ -212,8 +215,10 @@ class S3Storage extends AbstractData } catch (S3Exception $e) { error_log('failed to read ' . $pasteid . ' from ' . $this->_bucket . ', ' . trim(preg_replace('/\s\s+/', ' ', $e->getMessage()))); - return false; + } catch (JsonException $e) { + error_log('failed to JSON decode ' . $key . ', ' . $e->getMessage()); } + return false; } /** diff --git a/lib/Exception/JsonException.php b/lib/Exception/JsonException.php new file mode 100644 index 00000000..dc844a2d --- /dev/null +++ b/lib/Exception/JsonException.php @@ -0,0 +1,37 @@ +_error = 'Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.'; $this->logErrorWithClassName('Error calling proxy: ' . $e->getMessage()); return; diff --git a/lib/Proxy/ShlinkProxy.php b/lib/Proxy/ShlinkProxy.php index ee4507cf..639a957c 100644 --- a/lib/Proxy/ShlinkProxy.php +++ b/lib/Proxy/ShlinkProxy.php @@ -12,6 +12,7 @@ namespace PrivateBin\Proxy; use PrivateBin\Configuration; +use PrivateBin\Exception\JsonException; use PrivateBin\Json; /** @@ -48,12 +49,17 @@ class ShlinkProxy extends AbstractProxy 'longUrl' => $link, ); - return array( - 'method' => 'POST', - 'header' => "Content-Type: application/json\r\n" . - 'X-Api-Key: ' . $shlink_api_key . "\r\n", - 'content' => Json::encode($body), - ); + try { + return array( + 'method' => 'POST', + 'header' => "Content-Type: application/json\r\n" . + 'X-Api-Key: ' . $shlink_api_key . "\r\n", + 'content' => Json::encode($body), + ); + } catch (JsonException $e) { + error_log('[' . get_class($this) . '] Error encoding body: ' . $e->getMessage()); + return array(); + } } /** diff --git a/lib/Request.php b/lib/Request.php index 24a083be..fb6fb37c 100644 --- a/lib/Request.php +++ b/lib/Request.php @@ -11,7 +11,7 @@ namespace PrivateBin; -use Exception; +use PrivateBin\Exception\JsonException; use PrivateBin\Model\Paste; /** @@ -113,7 +113,7 @@ class Request try { $data = file_get_contents(self::$_inputStream); $this->_params = Json::decode($data); - } catch (Exception $e) { + } catch (JsonException $e) { // ignore error, $this->_params will remain empty } break; diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php index e842065d..b219f713 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -513,16 +513,19 @@ if ($FILEUPLOAD) : -