Skip to content
Snippets Groups Projects
Commit f15b893e authored by Jared Hancock's avatar Jared Hancock
Browse files

storage: Avoid using `strlen` to count bytes

For PHP installations that have `mbstring.func_overload` enabled (set to a
value including `2`), the `strlen` function will be overloaded to use the
`mb_strlen` equivalent. Problematically, the internal encoding of `UTF-8`
will be applied to all file content, which will count UTF-8 characters
rather than bytes. This will cause the data to be saved correctly; however,
the `size` recorded in the %file table will be recorded incorrectly.

This patch allows the backend to report the size of the contents saved with
the request and provides a failsafe mechanism which will use the mbstring
equivalent if available, and the mbstring version is coded to use the `8bit`
as the encoding which will prevent reading characters.

References:
https://github.com/osTicket/osTicket-1.8/issues/552
parent bdfb2f13
No related branches found
No related tags found
No related merge requests found
......@@ -307,21 +307,24 @@ class AttachmentFile {
= self::_getKeyAndHash($file['data']);
if (!$file['key'])
$file['key'] = $key;
if (!isset($file['size']))
$file['size'] = strlen($file['data']);
}
// Check and see if the file is already on record
$sql = 'SELECT id, `key` FROM '.FILE_TABLE
.' WHERE signature='.db_input($file['signature'])
.' AND size='.db_input($file['size']);
if (isset($file['size'])) {
// Check and see if the file is already on record
$sql = 'SELECT id, `key` FROM '.FILE_TABLE
.' WHERE signature='.db_input($file['signature'])
.' AND size='.db_input($file['size']);
// If the record exists in the database already, a file with the
// same hash and size is already on file -- just return its ID
if (list($id, $key) = db_fetch_row(db_query($sql))) {
$file['key'] = $key;
return $id;
// If the record exists in the database already, a file with the
// same hash and size is already on file -- just return its ID
if (list($id, $key) = db_fetch_row(db_query($sql))) {
$file['key'] = $key;
return $id;
}
}
elseif (!isset($file['data'])) {
// Unable to determine the file's size
return false;
}
if (!$file['type']) {
......@@ -337,15 +340,16 @@ class AttachmentFile {
$file['type'] = 'application/octet-stream';
}
$sql='INSERT INTO '.FILE_TABLE.' SET created=NOW() '
.',type='.db_input(strtolower($file['type']))
.',size='.db_input($file['size'])
.',name='.db_input($file['name'])
.',`key`='.db_input($file['key'])
.',ft='.db_input($ft ?: 'T')
.',signature='.db_input($file['signature']);
if (isset($file['size']))
$sql .= ',size='.db_input($file['size']);
if (!(db_query($sql) && ($id = db_insert_id())))
return false;
......@@ -383,8 +387,22 @@ class AttachmentFile {
return false;
}
$sql = 'UPDATE '.FILE_TABLE.' SET bk='.db_input($bk->getBkChar())
.' WHERE id='.db_input($f->getId());
$sql = 'UPDATE '.FILE_TABLE.' SET bk='.db_input($bk->getBkChar());
if (!isset($file['size'])) {
if ($size = $bk->getSize())
$file['size'] = $size;
// Prefer mb_strlen, because mbstring.func_overload will
// automatically prefer it if configured.
elseif (function_exists('mb_strlen'))
$file['size'] = mb_strlen($file['data'], '8bit');
else
$file['size'] = strlen($file['data']);
$sql .= ', `size`='.db_input($file['size']);
}
$sql .= ' WHERE id='.db_input($f->getId());
db_query($sql);
return $f->getId();
......@@ -745,6 +763,18 @@ class FileStorageBackend {
function getHashDigest($algo) {
return false;
}
/**
* getSize
*
* Retrieves the size of the contents written or available to be read.
* The backend should optimize this process if possible by keeping track
* of the bytes written in a way apart from `strlen`. This value will be
* used instead of inspecting the contents using `strlen`.
*/
function getSize() {
return false;
}
}
......@@ -764,7 +794,7 @@ class AttachmentChunkedData extends FileStorageBackend {
$this->_buffer = false;
}
function length() {
function getSize() {
list($length) = db_fetch_row(db_query(
'SELECT SUM(LENGTH(filedata)) FROM '.FILE_CHUNK_TABLE
.' WHERE file_id='.db_input($this->file->getId())));
......@@ -788,11 +818,12 @@ class AttachmentChunkedData extends FileStorageBackend {
function write($what, $chunk_size=CHUNK_SIZE) {
$offset=0;
$what = bin2hex($what);
for (;;) {
$block = substr($what, $offset, $chunk_size);
$block = substr($what, $offset, $chunk_size*2);
if (!$block) break;
if (!db_query('REPLACE INTO '.FILE_CHUNK_TABLE
.' SET filedata=0x'.bin2hex($block).', file_id='
.' SET filedata=0x'.$block.', file_id='
.db_input($this->file->getId()).', chunk_id='.db_input($this->_chunk++)))
return false;
$offset += strlen($block);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment