Merge pull request #36120 from nextcloud/enh/32bits-support

Fix 32bit support and add workflow for 32bits testing
pull/36524/head
Côme Chilliet 2023-02-07 14:08:08 +07:00 committed by GitHub
commit 4e969ef8a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
74 changed files with 363 additions and 207 deletions

@ -0,0 +1,58 @@
name: PHPUnit
on:
workflow_dispatch:
schedule:
- cron: "15 1 * * 1-6"
permissions:
contents: read
concurrency:
group: phpunit-32bits-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
phpunit-32bits:
runs-on: ubuntu-latest
container: shivammathur/node:latest-i386
strategy:
matrix:
php-versions: ['8.0']
steps:
- name: Checkout server
uses: actions/checkout@v3
with:
submodules: true
- name: Install tools
run: |
sudo apt-get update
sudo apt-get install -y ffmpeg imagemagick libmagickcore-6.q16-3-extra
- name: Set up php ${{ matrix.php-versions }}
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
extensions: ctype, curl, dom, fileinfo, gd, imagick, intl, json, mbstring, openssl, pdo_sqlite, posix, sqlite, xml, zip, apcu
tools: phpunit:9
coverage: none
ini-values:
apc.enabled=on,
apc.enable_cli=on
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Nextcloud
env:
DB_PORT: 4444
run: |
mkdir data
./occ maintenance:install --verbose --database=sqlite --database-name=nextcloud --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=autotest --database-pass=rootpassword --admin-user admin --admin-pass admin
php -f index.php
- name: PHPUnit
working-directory: tests
run: phpunit --configuration phpunit-autotest.xml --exclude-group PRIMARY-azure,PRIMARY-s3,PRIMARY-swift,Memcached,Redis,RoutingWeirdness

@ -64,3 +64,9 @@ jobs:
CONTENT=$(./client-cmd.sh ${{ env.DC_IP }} curl -b /shared/cookies/jar -s --negotiate -u testuser@DOMAIN.TEST: --delegation always http://httpd.domain.test/remote.php/webdav/smb/test.txt)
CONTENT=$(echo $CONTENT | head -n 1 | tr -d '[:space:]')
[[ $CONTENT == "testfile" ]]
- name: Show logs
if: failure()
run: |
docker exec --user 33 apache ./occ log:file
FILEPATH=$(docker exec --user 33 apache ./occ log:file | grep "Log file:" | cut -d' ' -f3)
docker exec --user 33 apache cat $FILEPATH

@ -72,7 +72,6 @@ use OCP\EventDispatcher\IEventDispatcher;
use OCP\IConfig;
use OCP\IDBConnection;
use OCP\IGroupManager;
use OCP\IUser;
use OCP\IUserManager;
use OCP\Security\ISecureRandom;
use Psr\Log\LoggerInterface;
@ -120,7 +119,6 @@ use function time;
* @package OCA\DAV\CalDAV
*/
class CalDavBackend extends AbstractBackend implements SyncSupport, SubscriptionSupport, SchedulingSupport {
use TTransactional;
public const CALENDAR_TYPE_CALENDAR = 0;
@ -346,7 +344,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
$row['principaluri'] = (string) $row['principaluri'];
$components = [];
if ($row['components']) {
$components = explode(',',$row['components']);
$components = explode(',', $row['components']);
}
$calendar = [
@ -420,7 +418,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
$row['displayname'] = $row['displayname'] . ' (' . ($this->userManager->getDisplayName($name) ?? ($name ?? '')) . ')';
$components = [];
if ($row['components']) {
$components = explode(',',$row['components']);
$components = explode(',', $row['components']);
}
$calendar = [
'id' => $row['id'],
@ -469,7 +467,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
$row['principaluri'] = (string) $row['principaluri'];
$components = [];
if ($row['components']) {
$components = explode(',',$row['components']);
$components = explode(',', $row['components']);
}
$calendar = [
'id' => $row['id'],
@ -521,7 +519,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
$row['displayname'] = $row['displayname'] . "($name)";
$components = [];
if ($row['components']) {
$components = explode(',',$row['components']);
$components = explode(',', $row['components']);
}
$calendar = [
'id' => $row['id'],
@ -586,7 +584,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
$row['displayname'] = $row['displayname'] . ' ' . "($name)";
$components = [];
if ($row['components']) {
$components = explode(',',$row['components']);
$components = explode(',', $row['components']);
}
$calendar = [
'id' => $row['id'],
@ -639,7 +637,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
$row['principaluri'] = (string) $row['principaluri'];
$components = [];
if ($row['components']) {
$components = explode(',',$row['components']);
$components = explode(',', $row['components']);
}
$calendar = [
@ -687,7 +685,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
$row['principaluri'] = (string) $row['principaluri'];
$components = [];
if ($row['components']) {
$components = explode(',',$row['components']);
$components = explode(',', $row['components']);
}
$calendar = [
@ -779,7 +777,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
if (!($properties[$sccs] instanceof SupportedCalendarComponentSet)) {
throw new DAV\Exception('The ' . $sccs . ' property must be of type: \Sabre\CalDAV\Property\SupportedCalendarComponentSet');
}
$values['components'] = implode(',',$properties[$sccs]->getValue());
$values['components'] = implode(',', $properties[$sccs]->getValue());
} elseif (isset($properties['components'])) {
// Allow to provide components internally without having
// to create a SupportedCalendarComponentSet object
@ -797,7 +795,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
}
}
[$calendarId, $calendarData] = $this->atomic(function() use ($values) {
[$calendarId, $calendarData] = $this->atomic(function () use ($values) {
$query = $this->db->getQueryBuilder();
$query->insert('calendars');
foreach ($values as $column => $value) {
@ -1712,7 +1710,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
$query->expr()->eq('c.calendarid',
$query->createNamedParameter($id)),
$query->expr()->eq('c.calendartype',
$query->createNamedParameter(self::CALENDAR_TYPE_CALENDAR)));
$query->createNamedParameter(self::CALENDAR_TYPE_CALENDAR)));
}
foreach ($sharedCalendars as $id) {
$calendarExpressions[] = $query->expr()->andX(
@ -1860,7 +1858,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
}
}
if(isset($options['uid'])) {
if (isset($options['uid'])) {
$outerQuery->andWhere($outerQuery->expr()->eq('uid', $outerQuery->createNamedParameter($options['uid'])));
}
@ -2435,7 +2433,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
}
}
[$subscriptionId, $subscriptionRow] = $this->atomic(function() use ($values) {
[$subscriptionId, $subscriptionRow] = $this->atomic(function () use ($values) {
$valuesToInsert = [];
$query = $this->db->getQueryBuilder();
foreach (array_keys($values) as $name) {

@ -138,7 +138,7 @@ class File extends Node implements IFile {
public function put($data) {
try {
$exists = $this->fileView->file_exists($this->path);
if ($this->info && $exists && !$this->info->isUpdateable()) {
if ($exists && !$this->info->isUpdateable()) {
throw new Forbidden();
}
} catch (StorageNotAvailableException $e) {
@ -759,9 +759,6 @@ class File extends Node implements IFile {
* @return string|null
*/
public function getChecksum() {
if (!$this->info) {
return null;
}
return $this->info->getChecksum();
}

@ -53,10 +53,8 @@ use Sabre\DAV\Server;
use Sabre\DAV\Tree;
use Sabre\HTTP\RequestInterface;
use Sabre\HTTP\ResponseInterface;
use Sabre\Uri;
class FilesPlugin extends ServerPlugin {
// namespace
public const NS_OWNCLOUD = 'http://owncloud.org/ns';
public const NS_NEXTCLOUD = 'http://nextcloud.org/ns';
@ -352,7 +350,7 @@ class FilesPlugin extends ServerPlugin {
$propFind->handle(self::HAS_PREVIEW_PROPERTYNAME, function () use ($node) {
return json_encode($this->previewManager->isAvailable($node->getFileInfo()), JSON_THROW_ON_ERROR);
});
$propFind->handle(self::SIZE_PROPERTYNAME, function () use ($node): ?int {
$propFind->handle(self::SIZE_PROPERTYNAME, function () use ($node): int|float {
return $node->getSize();
});
$propFind->handle(self::MOUNT_TYPE_PROPERTYNAME, function () use ($node) {
@ -382,7 +380,7 @@ class FilesPlugin extends ServerPlugin {
});
/**
* Return file/folder name as displayname. The primary reason to
* implement it this way is to avoid costly fallback to
* implement it this way is to avoid costly fallback to
* CustomPropertiesBackend (esp. visible when querying all files
* in a folder).
*/

@ -44,14 +44,12 @@ use OCP\Files\DavUtil;
use OCP\Files\FileInfo;
use OCP\Files\IRootFolder;
use OCP\Files\StorageNotAvailableException;
use OCP\Share\IShare;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IManager;
abstract class Node implements \Sabre\DAV\INode {
/**
* @var \OC\Files\View
* @var View
*/
protected $fileView;
@ -69,10 +67,7 @@ abstract class Node implements \Sabre\DAV\INode {
*/
protected $property_cache = null;
/**
* @var \OCP\Files\FileInfo
*/
protected $info;
protected FileInfo $info;
/**
* @var IManager
@ -83,10 +78,6 @@ abstract class Node implements \Sabre\DAV\INode {
/**
* Sets up the node, expects a full path name
*
* @param \OC\Files\View $view
* @param \OCP\Files\FileInfo $info
* @param IManager $shareManager
*/
public function __construct(View $view, FileInfo $info, IManager $shareManager = null) {
$this->fileView = $view;
@ -109,8 +100,12 @@ abstract class Node implements \Sabre\DAV\INode {
}
}
protected function refreshInfo() {
$this->info = $this->fileView->getFileInfo($this->path);
protected function refreshInfo(): void {
$info = $this->fileView->getFileInfo($this->path);
if ($info === false) {
throw new \Sabre\DAV\Exception('Failed to get fileinfo for '. $this->path);
}
$this->info = $info;
$root = \OC::$server->get(IRootFolder::class);
if ($this->info->getType() === FileInfo::TYPE_FOLDER) {
$this->node = new Folder($root, $this->fileView, $this->path, $this->info);
@ -145,7 +140,6 @@ abstract class Node implements \Sabre\DAV\INode {
* @throws \Sabre\DAV\Exception\Forbidden
*/
public function setName($name) {
// rename is only allowed if the update privilege is granted
if (!($this->info->isUpdateable() || ($this->info->getMountPoint() instanceof MoveableMount && $this->info->getInternalPath() === ''))) {
throw new \Sabre\DAV\Exception\Forbidden();
@ -233,9 +227,10 @@ abstract class Node implements \Sabre\DAV\INode {
/**
* Returns the size of the node, in bytes
*
* @return integer
* @psalm-suppress ImplementedReturnTypeMismatch \Sabre\DAV\IFile::getSize signature does not support 32bit
* @return int|float
*/
public function getSize() {
public function getSize(): int|float {
return $this->info->getSize();
}
@ -271,7 +266,6 @@ abstract class Node implements \Sabre\DAV\INode {
* @return int
*/
public function getSharePermissions($user) {
// check of we access a federated share
if ($user !== null) {
try {

@ -178,7 +178,7 @@ class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
* This method is called before any HTTP method and validates there is enough free space to store the file
*
* @param string $path relative to the users home
* @param int $length
* @param int|float|null $length
* @throws InsufficientStorage
* @return bool
*/

@ -77,6 +77,10 @@ class DirectFile implements IFile {
return $this->file->getEtag();
}
/**
* @psalm-suppress ImplementedReturnTypeMismatch \Sabre\DAV\IFile::getSize signature does not support 32bit
* @return int|float
*/
public function getSize() {
$this->getFile();

@ -29,7 +29,6 @@ use OCA\DAV\Connector\Sabre\File;
use Sabre\DAV\IFile;
class UploadFile implements IFile {
/** @var File */
private $file;
@ -53,6 +52,10 @@ class UploadFile implements IFile {
return $this->file->getETag();
}
/**
* @psalm-suppress ImplementedReturnTypeMismatch \Sabre\DAV\IFile::getSize signature does not support 32bit
* @return int|float
*/
public function getSize() {
return $this->file->getSize();
}

@ -125,7 +125,6 @@ class CalDavBackendTest extends AbstractCalDavBackend {
* @dataProvider providesSharingData
*/
public function testCalendarSharing($userCanRead, $userCanWrite, $groupCanRead, $groupCanWrite, $add): void {
/** @var IL10N|\PHPUnit\Framework\MockObject\MockObject $l10n */
$l10n = $this->createMock(IL10N::class);
$l10n
@ -423,7 +422,12 @@ EOD;
$events[0] = $this->createEvent($calendarId, '20130912T130000Z', '20130912T140000Z');
$events[1] = $this->createEvent($calendarId, '20130912T150000Z', '20130912T170000Z');
$events[2] = $this->createEvent($calendarId, '20130912T173000Z', '20130912T220000Z');
$events[3] = $this->createEvent($calendarId, '21130912T130000Z', '22130912T130000Z');
if (PHP_INT_SIZE > 8) {
$events[3] = $this->createEvent($calendarId, '21130912T130000Z', '22130912T130000Z');
} else {
/* On 32bit we do not support events after 2038 */
$events[3] = $this->createEvent($calendarId, '20370912T130000Z', '20370912T130000Z');
}
$result = $this->backend->calendarQuery($calendarId, [
'name' => '',
@ -471,7 +475,7 @@ EOD;
'only-events' => [[0, 1, 2, 3], [], [['name' => 'VEVENT', 'is-not-defined' => false, 'comp-filters' => [], 'time-range' => ['start' => null, 'end' => null], 'prop-filters' => []]],],
'start' => [[1, 2, 3], [], [['name' => 'VEVENT', 'is-not-defined' => false, 'comp-filters' => [], 'time-range' => ['start' => new DateTime('2013-09-12 14:00:00', new DateTimeZone('UTC')), 'end' => null], 'prop-filters' => []]],],
'end' => [[0], [], [['name' => 'VEVENT', 'is-not-defined' => false, 'comp-filters' => [], 'time-range' => ['start' => null, 'end' => new DateTime('2013-09-12 14:00:00', new DateTimeZone('UTC'))], 'prop-filters' => []]],],
'future' => [[3], [], [['name' => 'VEVENT', 'is-not-defined' => false, 'comp-filters' => [], 'time-range' => ['start' => new DateTime('2099-09-12 14:00:00', new DateTimeZone('UTC')), 'end' => null], 'prop-filters' => []]],],
'future' => [[3], [], [['name' => 'VEVENT', 'is-not-defined' => false, 'comp-filters' => [], 'time-range' => ['start' => new DateTime('2036-09-12 14:00:00', new DateTimeZone('UTC')), 'end' => null], 'prop-filters' => []]],],
];
}
@ -648,8 +652,15 @@ EOS;
* @dataProvider providesCalDataForGetDenormalizedData
*/
public function testGetDenormalizedData($expected, $key, $calData): void {
$actual = $this->backend->getDenormalizedData($calData);
$this->assertEquals($expected, $actual[$key]);
try {
$actual = $this->backend->getDenormalizedData($calData);
$this->assertEquals($expected, $actual[$key]);
} catch (\ValueError $e) {
if (($e->getMessage() === 'Epoch doesn\'t fit in a PHP integer') && (PHP_INT_SIZE < 8)) {
$this->markTestSkipped('This fail on 32bits because of PHP limitations in DateTime');
}
throw $e;
}
}
public function providesCalDataForGetDenormalizedData() {

@ -228,13 +228,13 @@ class FilesPluginTest extends TestCase {
$this->assertEquals('00000123instanceid', $propFind->get(self::FILEID_PROPERTYNAME));
$this->assertEquals('123', $propFind->get(self::INTERNAL_FILEID_PROPERTYNAME));
$this->assertEquals('1973-11-29T21:33:09+00:00', $propFind->get(self::CREATIONDATE_PROPERTYNAME));
$this->assertEquals(null, $propFind->get(self::SIZE_PROPERTYNAME));
$this->assertEquals(0, $propFind->get(self::SIZE_PROPERTYNAME));
$this->assertEquals('DWCKMSR', $propFind->get(self::PERMISSIONS_PROPERTYNAME));
$this->assertEquals('http://example.com/', $propFind->get(self::DOWNLOADURL_PROPERTYNAME));
$this->assertEquals('foo', $propFind->get(self::OWNER_ID_PROPERTYNAME));
$this->assertEquals('M. Foo', $propFind->get(self::OWNER_DISPLAY_NAME_PROPERTYNAME));
$this->assertEquals('my_fingerprint', $propFind->get(self::DATA_FINGERPRINT_PROPERTYNAME));
$this->assertEquals([self::SIZE_PROPERTYNAME], $propFind->get404Properties());
$this->assertEquals([], $propFind->get404Properties());
}
public function testGetPropertiesStorageNotAvailable(): void {

@ -261,6 +261,8 @@ class FilesReportPluginTest extends \Test\TestCase {
$filesNode2 = $this->getMockBuilder(File::class)
->disableOriginalConstructor()
->getMock();
$filesNode2->method('getSize')
->willReturn(10);
$this->userFolder->expects($this->exactly(2))
->method('getById')

@ -40,12 +40,12 @@ namespace OCA\Files\AppInfo;
use OCA\Files\Controller\OpenLocalEditorController;
// Legacy routes above
/** @var $this \OC\Route\Router */
/** @var \OC\Route\Router $this */
$this->create('files_ajax_download', 'apps/files/ajax/download.php')
->actionInclude('files/ajax/download.php');
/** @var Application $application */
$application = \OC::$server->query(Application::class);
$application = \OC::$server->get(Application::class);
$application->registerRoutes(
$this,
[

@ -93,7 +93,10 @@ class HelperTest extends \Test\TestCase {
/**
* @dataProvider sortDataProvider
*/
public function testSortByName($sort, $sortDescending, $expectedOrder) {
public function testSortByName(string $sort, bool $sortDescending, array $expectedOrder) {
if (($sort === 'mtime') && (PHP_INT_SIZE < 8)) {
$this->markTestSkipped('Skip mtime sorting on 32bit');
}
$files = self::getTestFileList();
$files = \OCA\Files\Helper::sortFiles($files, $sort, $sortDescending);
$fileNames = [];

@ -140,7 +140,7 @@ class FTP extends Common {
}
}
public function filesize($path) {
public function filesize($path): false|int|float {
$result = $this->getConnection()->size($this->buildPath($path));
if ($result === -1) {
return false;

@ -205,6 +205,9 @@ class ApiTest extends TestCase {
$ocs->cleanup();
}
/**
* @group RoutingWeirdness
*/
public function testCreateShareLink() {
$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
$result = $ocs->createShare($this->folder, \OCP\Constants::PERMISSION_ALL, IShare::TYPE_LINK);
@ -227,6 +230,9 @@ class ApiTest extends TestCase {
$ocs->cleanup();
}
/**
* @group RoutingWeirdness
*/
public function testCreateShareLinkPublicUpload() {
$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
$result = $ocs->createShare($this->folder, \OCP\Constants::PERMISSION_ALL, IShare::TYPE_LINK, null, 'true');
@ -419,6 +425,7 @@ class ApiTest extends TestCase {
/**
* @medium
* @group RoutingWeirdness
*/
public function testPublicLinkUrl() {
$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
@ -837,7 +844,7 @@ class ApiTest extends TestCase {
// $request = $this->createRequest(['path' => $this->subfolder]);
$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER2);
$result1 = $ocs->getShares('false','false','false', $this->subfolder);
$result1 = $ocs->getShares('false', 'false', 'false', $this->subfolder);
$ocs->cleanup();
// test should return one share within $this->folder
@ -1050,10 +1057,10 @@ class ApiTest extends TestCase {
$config->setAppValue('core', 'shareapi_enforce_expire_date', 'yes');
$dateWithinRange = new \DateTime();
$dateWithinRange->setTime(0,0,0);
$dateWithinRange->setTime(0, 0, 0);
$dateWithinRange->add(new \DateInterval('P5D'));
$dateOutOfRange = new \DateTime();
$dateOutOfRange->setTime(0,0,0);
$dateOutOfRange->setTime(0, 0, 0);
$dateOutOfRange->add(new \DateInterval('P8D'));
// update expire date to a valid value
@ -1290,6 +1297,7 @@ class ApiTest extends TestCase {
* Make sure only ISO 8601 dates are accepted
*
* @dataProvider datesProvider
* @group RoutingWeirdness
*/
public function testPublicLinkExpireDate($date, $valid) {
$ocs = $this->createOCS(self::TEST_FILES_SHARING_API_USER1);
@ -1320,6 +1328,9 @@ class ApiTest extends TestCase {
$this->shareManager->deleteShare($share);
}
/**
* @group RoutingWeirdness
*/
public function testCreatePublicLinkExpireDateValid() {
$config = \OC::$server->getConfig();
@ -1343,7 +1354,7 @@ class ApiTest extends TestCase {
$this->assertEquals($url, $data['url']);
$share = $this->shareManager->getShareById('ocinternal:'.$data['id']);
$date->setTime(0,0,0);
$date->setTime(0, 0, 0);
$this->assertEquals($date, $share->getExpirationDate());
$this->shareManager->deleteShare($share);

@ -57,7 +57,11 @@ abstract class AbstractTrash implements ITrash {
return $this->data;
}
public function getSize(): int {
/**
* @psalm-suppress ImplementedReturnTypeMismatch \Sabre\DAV\IFile::getSize signature does not support 32bit
* @return int|float
*/
public function getSize(): int|float {
return $this->data->getSize();
}

@ -39,7 +39,7 @@ interface ITrash {
public function getDeletionTime(): int;
public function getSize();
public function getSize(): int|float;
public function getFileId(): int;

@ -33,7 +33,6 @@ use OCP\IConfig;
use OCP\IUserManager;
use PHPUnit\Framework\MockObject\MockObject;
use Test\TestCase;
use Psr\Log\LoggerInterface;
class ExpireTrashTest extends TestCase {
/** @var IConfig|MockObject */
@ -61,7 +60,7 @@ class ExpireTrashTest extends TestCase {
$this->time = $this->createMock(ITimeFactory::class);
$this->time->method('getTime')
->willReturn(99999999999);
->willReturn(999999999);
$this->jobList->expects($this->once())
->method('setLastRun');

@ -36,8 +36,8 @@ use OCP\DB\Types;
* @method void setFileId(int $fileId)
* @method int getTimestamp()
* @method void setTimestamp(int $timestamp)
* @method int getSize()
* @method void setSize(int $size)
* @method int|float getSize()
* @method void setSize(int|float $size)
* @method int getMimetype()
* @method void setMimetype(int $mimetype)
* @method array|null getMetadata()
@ -78,4 +78,4 @@ class VersionEntity extends Entity implements JsonSerializable {
$this->metadata['label'] = $label;
$this->markFieldUpdated('metadata');
}
}
}

@ -68,7 +68,11 @@ class VersionFile implements IFile {
return (string)$this->version->getRevisionId();
}
public function getSize(): int {
/**
* @psalm-suppress ImplementedReturnTypeMismatch \Sabre\DAV\IFile::getSize signature does not support 32bit
* @return int|float
*/
public function getSize(): int|float {
return $this->version->getSize();
}

@ -65,10 +65,10 @@ interface IVersion {
/**
* Get the size of this version
*
* @return int
* @return int|float
* @since 15.0.0
*/
public function getSize(): int;
public function getSize(): int|float;
/**
* Get the name of the source file at the time of making this version

@ -40,7 +40,7 @@ class Version implements IVersion, INameableVersion {
private string $label;
/** @var int */
/** @var int|float */
private $size;
/** @var string */
@ -62,7 +62,7 @@ class Version implements IVersion, INameableVersion {
int $timestamp,
$revisionId,
string $name,
int $size,
int|float $size,
string $mimetype,
string $path,
FileInfo $sourceFileInfo,
@ -98,7 +98,7 @@ class Version implements IVersion, INameableVersion {
return $this->timestamp;
}
public function getSize(): int {
public function getSize(): int|float {
return $this->size;
}

@ -33,7 +33,6 @@ use PHPUnit\Framework\MockObject\MockObject;
use Test\TestCase;
class ExpireVersionsTest extends TestCase {
/** @var IConfig|MockObject */
private $config;
@ -70,7 +69,7 @@ class ExpireVersionsTest extends TestCase {
$timeFactory = $this->createMock(ITimeFactory::class);
$timeFactory->method('getTime')
->with()
->willReturn(99999999999);
->willReturn(999999999);
$job = new ExpireVersions($this->config, $this->userManager, $this->expiration, $timeFactory);
$job->start($this->jobList);

@ -73,7 +73,6 @@ use Psr\Log\LoggerInterface;
use Test\TestCase;
class UsersControllerTest extends TestCase {
/** @var IUserManager|MockObject */
protected $userManager;
/** @var IConfig|MockObject */
@ -497,7 +496,7 @@ class UsersControllerTest extends TestCase {
->method('generate')
->with(10)
->willReturnCallback(function () {
return (string)rand(1000000000, 9999999999);
return (string)rand(100000000, 999999999);
});
$this->assertTrue(key_exists(

@ -115,14 +115,12 @@ class File extends Command implements Completion\CompletionAwareInterface {
}
/**
* @param mixed $rotateSize
* @throws \InvalidArgumentException
*/
protected function validateRotateSize(&$rotateSize) {
protected function validateRotateSize(false|int|float $rotateSize): void {
if ($rotateSize === false) {
throw new \InvalidArgumentException('Error parsing log rotation file size');
}
$rotateSize = (int) $rotateSize;
if ($rotateSize < 0) {
throw new \InvalidArgumentException('Log rotation file size must be non-negative');
}

@ -50,9 +50,8 @@ abstract class Archive {
/**
* get the uncompressed size of a file in the archive
* @return int|false
*/
abstract public function filesize(string $path);
abstract public function filesize(string $path): false|int|float;
/**
* get the last modified time of a file in the archive

@ -165,10 +165,8 @@ class TAR extends Archive {
/**
* get the uncompressed size of a file in the archive
*
* @return int|false
*/
public function filesize(string $path) {
public function filesize(string $path): false|int|float {
$stat = $this->getHeader($path);
return $stat['size'] ?? false;
}

@ -91,9 +91,8 @@ class ZIP extends Archive {
/**
* get the uncompressed size of a file in the archive
* @return int|false
*/
public function filesize(string $path) {
public function filesize(string $path): false|int|float {
$stat = $this->zip->statName($path);
return $stat['size'] ?? false;
}

@ -81,10 +81,8 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
/**
* The size of the file/folder without any sub mount
*
* @var int
*/
private $rawSize = 0;
private int|float $rawSize = 0;
/**
* @param string|boolean $path
@ -207,7 +205,8 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
}
/**
* @return int
* @param bool $includeMounts
* @return int|float
*/
public function getSize($includeMounts = true) {
if ($includeMounts) {

@ -730,7 +730,7 @@ class Filesystem {
* get the filesystem info
*
* @param string $path
* @param boolean $includeMountPoints whether to add mountpoint sizes,
* @param bool|string $includeMountPoints whether to add mountpoint sizes,
* defaults to true
* @return \OC\Files\FileInfo|false False if file does not exist
*/

@ -225,7 +225,7 @@ class LazyFolder implements \OCP\Files\Folder {
/**
* @inheritDoc
*/
public function getSize($includeMounts = true) {
public function getSize($includeMounts = true): int|float {
return $this->__call(__FUNCTION__, func_get_args());
}

@ -209,11 +209,11 @@ class Node implements \OCP\Files\Node {
/**
* @param bool $includeMounts
* @return int
* @return int|float
* @throws InvalidPathException
* @throws NotFoundException
*/
public function getSize($includeMounts = true) {
public function getSize($includeMounts = true): int|float {
return $this->getFileInfo()->getSize($includeMounts);
}

@ -65,7 +65,7 @@ class NonExistingFile extends File {
}
}
public function getSize($includeMounts = true) {
public function getSize($includeMounts = true): int|float {
if ($this->fileInfo) {
return parent::getSize($includeMounts);
} else {

@ -66,7 +66,7 @@ class NonExistingFolder extends Folder {
}
}
public function getSize($includeMounts = true) {
public function getSize($includeMounts = true): int|float {
if ($this->fileInfo) {
return parent::getSize($includeMounts);
} else {

@ -290,9 +290,9 @@ class Root extends Folder implements IRootFolder {
/**
* @param bool $includeMounts
* @return int
* @return int|float
*/
public function getSize($includeMounts = true) {
public function getSize($includeMounts = true): int|float {
return 0;
}

@ -56,7 +56,7 @@ class NewSimpleFile implements ISimpleFile {
/**
* Get the size in bytes
*/
public function getSize(): int {
public function getSize(): int|float {
if ($this->file) {
return $this->file->getSize();
} else {

@ -46,7 +46,7 @@ class SimpleFile implements ISimpleFile {
/**
* Get the size in bytes
*/
public function getSize(): int {
public function getSize(): int|float {
return $this->file->getSize();
}

@ -121,7 +121,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage {
return $this->filetype($path) === 'file';
}
public function filesize($path) {
public function filesize($path): false|int|float {
if ($this->is_dir($path)) {
return 0; //by definition
} else {
@ -695,9 +695,9 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage {
$result = $this->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, true);
if ($result) {
if ($sourceStorage->is_dir($sourceInternalPath)) {
$result = $result && $sourceStorage->rmdir($sourceInternalPath);
$result = $sourceStorage->rmdir($sourceInternalPath);
} else {
$result = $result && $sourceStorage->unlink($sourceInternalPath);
$result = $sourceStorage->unlink($sourceInternalPath);
}
}
return $result;

@ -80,7 +80,7 @@ class FailedStorage extends Common {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}
public function filesize($path) {
public function filesize($path): false|int|float {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}

@ -171,6 +171,11 @@ class Local extends \OC\Files\Storage\Common {
return false;
}
$statResult = @stat($fullPath);
if (PHP_INT_SIZE === 4 && $statResult && !$this->is_dir($path)) {
$filesize = $this->filesize($path);
$statResult['size'] = $filesize;
$statResult[7] = $filesize;
}
if (is_array($statResult)) {
$statResult['full_path'] = $fullPath;
}
@ -237,11 +242,15 @@ class Local extends \OC\Files\Storage\Common {
return $filetype;
}
public function filesize($path) {
public function filesize($path): false|int|float {
if (!$this->is_file($path)) {
return 0;
}
$fullPath = $this->getSourcePath($path);
if (PHP_INT_SIZE === 4) {
$helper = new \OC\LargeFileHelper;
return $helper->getFileSize($fullPath) ?? false;
}
return filesize($fullPath);
}
@ -263,6 +272,10 @@ class Local extends \OC\Files\Storage\Common {
if (!$this->file_exists($path)) {
return false;
}
if (PHP_INT_SIZE === 4) {
$helper = new \OC\LargeFileHelper();
return $helper->getFileMtime($fullPath);
}
return filemtime($fullPath);
}

@ -165,7 +165,7 @@ class Availability extends Wrapper {
}
/** {@inheritdoc} */
public function filesize($path) {
public function filesize($path): false|int|float {
$this->checkAvailability();
try {
return parent::filesize($path);
@ -451,6 +451,9 @@ class Availability extends Wrapper {
}
/**
* @template T of StorageNotAvailableException|null
* @param T $e
* @psalm-return (T is null ? void : never)
* @throws StorageNotAvailableException
*/
protected function setUnavailable(?StorageNotAvailableException $e): void {

@ -210,11 +210,8 @@ class Encoding extends Wrapper {
/**
* see https://www.php.net/manual/en/function.filesize.php
* The result for filesize when called on a folder is required to be 0
*
* @param string $path
* @return int|bool
*/
public function filesize($path) {
public function filesize($path): false|int|float {
return $this->storage->filesize($this->findPathToUse($path));
}

@ -133,11 +133,8 @@ class Encryption extends Wrapper {
/**
* see https://www.php.net/manual/en/function.filesize.php
* The result for filesize when called on a folder is required to be 0
*
* @param string $path
* @return int
*/
public function filesize($path) {
public function filesize($path): false|int|float {
$fullPath = $this->getFullPath($path);
/** @var CacheEntry $info */

@ -158,11 +158,8 @@ class Jail extends Wrapper {
/**
* see https://www.php.net/manual/en/function.filesize.php
* The result for filesize when called on a folder is required to be 0
*
* @param string $path
* @return int|bool
*/
public function filesize($path) {
public function filesize($path): false|int|float {
return $this->getWrapperStorage()->filesize($this->getUnjailedPath($path));
}

@ -148,11 +148,8 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea
/**
* see https://www.php.net/manual/en/function.filesize.php
* The result for filesize when called on a folder is required to be 0
*
* @param string $path
* @return int|bool
*/
public function filesize($path) {
public function filesize($path): false|int|float {
return $this->getWrapperStorage()->filesize($path);
}

@ -143,8 +143,8 @@ class Encryption extends Wrapper {
* @param \OC\Encryption\Util $util
* @param \OC\Encryption\File $file
* @param string $mode
* @param int $size
* @param int $unencryptedSize
* @param int|float $size
* @param int|float $unencryptedSize
* @param int $headerSize
* @param bool $signed
* @param string $wrapper stream wrapper class
@ -158,7 +158,7 @@ class Encryption extends Wrapper {
\OC\Files\Storage\Storage $storage,
\OC\Files\Storage\Wrapper\Encryption $encStorage,
\OC\Encryption\Util $util,
\OC\Encryption\File $file,
\OC\Encryption\File $file,
$mode,
$size,
$unencryptedSize,

@ -411,7 +411,7 @@ class View {
* @param string $path
* @return mixed
*/
public function filesize($path) {
public function filesize(string $path) {
return $this->basicOperation('filesize', $path);
}
@ -1372,9 +1372,8 @@ class View {
* get the filesystem info
*
* @param string $path
* @param boolean|string $includeMountPoints true to add mountpoint sizes,
* @param bool|string $includeMountPoints true to add mountpoint sizes,
* 'ext' to add only ext storage mount point sizes. Defaults to true.
* defaults to true
* @return \OC\Files\FileInfo|false False if file does not exist
*/
public function getFileInfo($path, $includeMountPoints = true) {

@ -73,7 +73,7 @@ class LargeFileHelper {
*
* @return string Unsigned integer base-10 string
*/
public function formatUnsignedInteger($number) {
public function formatUnsignedInteger(int|float|string $number): string {
if (is_float($number)) {
// Undo the effect of the php.ini setting 'precision'.
return number_format($number, 0, '', '');
@ -98,7 +98,7 @@ class LargeFileHelper {
* @return null|int|float Number of bytes as number (float or int) or
* null on failure.
*/
public function getFileSize($filename) {
public function getFileSize(string $filename): null|int|float {
$fileSize = $this->getFileSizeViaCurl($filename);
if (!is_null($fileSize)) {
return $fileSize;
@ -118,7 +118,7 @@ class LargeFileHelper {
* @return null|int|float Number of bytes as number (float or int) or
* null on failure.
*/
public function getFileSizeViaCurl($fileName) {
public function getFileSizeViaCurl(string $fileName): null|int|float {
if (\OC::$server->get(IniGetWrapper::class)->getString('open_basedir') === '') {
$encodedFileName = rawurlencode($fileName);
$ch = curl_init("file:///$encodedFileName");
@ -146,7 +146,7 @@ class LargeFileHelper {
* @return null|int|float Number of bytes as number (float or int) or
* null on failure.
*/
public function getFileSizeViaExec($filename) {
public function getFileSizeViaExec(string $filename): null|int|float {
if (\OCP\Util::isFunctionEnabled('exec')) {
$os = strtolower(php_uname('s'));
$arg = escapeshellarg($filename);
@ -171,7 +171,7 @@ class LargeFileHelper {
*
* @return int|float Number of bytes as number (float or int).
*/
public function getFileSizeNative($filename) {
public function getFileSizeNative(string $filename): int|float {
$result = filesize($filename);
if ($result < 0) {
// For file sizes between 2 GiB and 4 GiB, filesize() will return a
@ -184,13 +184,10 @@ class LargeFileHelper {
/**
* Returns the current mtime for $fullPath
*
* @param string $fullPath
* @return int
*/
public function getFileMtime($fullPath) {
public function getFileMtime(string $fullPath): int {
try {
$result = filemtime($fullPath);
$result = filemtime($fullPath) ?: -1;
} catch (\Exception $e) {
$result = - 1;
}
@ -198,14 +195,14 @@ class LargeFileHelper {
if (\OCP\Util::isFunctionEnabled('exec')) {
$os = strtolower(php_uname('s'));
if (strpos($os, 'linux') !== false) {
return $this->exec('stat -c %Y ' . escapeshellarg($fullPath));
return (int)($this->exec('stat -c %Y ' . escapeshellarg($fullPath)) ?? -1);
}
}
}
return $result;
}
protected function exec($cmd) {
protected function exec(string $cmd): null|int|float {
$result = trim(exec($cmd));
return ctype_digit($result) ? 0 + $result : null;
}

@ -65,7 +65,7 @@ class NullStorage extends Common {
return ($path === '') ? 'dir' : false;
}
public function filesize($path) {
public function filesize($path): false|int|float {
throw new \OC\ForbiddenException('This request is not allowed to access the filesystem');
}

@ -24,8 +24,11 @@ declare(strict_types=1);
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OC;
use OCP\Util;
/**
* Helper class that covers memory info.
*/
@ -45,14 +48,14 @@ class MemoryInfo {
/**
* Returns the php memory limit.
*
* @return int The memory limit in bytes.
* @return int|float The memory limit in bytes.
*/
public function getMemoryLimit(): int {
public function getMemoryLimit(): int|float {
$iniValue = trim(ini_get('memory_limit'));
if ($iniValue === '-1') {
return -1;
} elseif (is_numeric($iniValue) === true) {
return (int)$iniValue;
} elseif (is_numeric($iniValue)) {
return Util::numericToNumber($iniValue);
} else {
return $this->memoryLimitToBytes($iniValue);
}
@ -62,11 +65,15 @@ class MemoryInfo {
* Converts the ini memory limit to bytes.
*
* @param string $memoryLimit The "memory_limit" ini value
* @return int
*/
private function memoryLimitToBytes(string $memoryLimit): int {
private function memoryLimitToBytes(string $memoryLimit): int|float {
$last = strtolower(substr($memoryLimit, -1));
$memoryLimit = (int)substr($memoryLimit, 0, -1);
$number = substr($memoryLimit, 0, -1);
if (is_numeric($number)) {
$memoryLimit = Util::numericToNumber($number);
} else {
throw new \InvalidArgumentException($number.' is not a valid numeric string (in memory_limit ini directive)');
}
// intended fall through
switch ($last) {

@ -247,13 +247,14 @@ class Setup {
];
}
if (PHP_INT_SIZE < 8) {
if ($this->iniWrapper->getString('open_basedir') !== '' && PHP_INT_SIZE === 4) {
$errors[] = [
'error' => $this->l10n->t(
'It seems that this %s instance is running on a 32-bit PHP environment. 64-bit is required for 26 and higher.',
'It seems that this %s instance is running on a 32-bit PHP environment and the open_basedir has been configured in php.ini. ' .
'This will lead to problems with files over 4 GB and is highly discouraged.',
[$this->defaults->getProductName()]
),
'hint' => $this->l10n->t('Please switch to 64-bit PHP.'),
'hint' => $this->l10n->t('Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP.'),
];
}

@ -40,7 +40,7 @@ use ZipStreamer\ZipStreamer;
class Streamer {
// array of regexp. Matching user agents will get tar instead of zip
private $preferTarFor = [ '/macintosh|mac os x/i' ];
private array $preferTarFor = [ '/macintosh|mac os x/i' ];
// streamer instance
private $streamerInstance;
@ -49,11 +49,11 @@ class Streamer {
* Streamer constructor.
*
* @param IRequest $request
* @param int $size The size of the files in bytes
* @param int|float $size The size of the files in bytes
* @param int $numberOfFiles The number of files (and directories) that will
* be included in the streamed file
*/
public function __construct(IRequest $request, int $size, int $numberOfFiles) {
public function __construct(IRequest $request, int|float $size, int $numberOfFiles) {
/**
* zip32 constraints for a basic (without compression, volumes nor
* encryption) zip file according to the Zip specification:
@ -85,7 +85,7 @@ class Streamer {
} elseif ($request->isUserAgent($this->preferTarFor)) {
$this->streamerInstance = new TarStreamer();
} else {
$this->streamerInstance = new ZipStreamer(['zip64' => true]);
$this->streamerInstance = new ZipStreamer(['zip64' => PHP_INT_SIZE !== 4]);
}
}
@ -149,11 +149,11 @@ class Streamer {
*
* @param resource $stream Stream to read data from
* @param string $internalName Filepath and name to be used in the archive.
* @param int $size Filesize
* @param int|bool $time File mtime as int, or false
* @param int|float $size Filesize
* @param int|false $time File mtime as int, or false
* @return bool $success
*/
public function addFileFromStream($stream, string $internalName, int $size, $time): bool {
public function addFileFromStream($stream, string $internalName, int|float $size, $time): bool {
$options = [];
if ($time) {
$options = [

@ -513,13 +513,17 @@ class User implements IUser {
*
* @param string $quota
* @return void
* @throws InvalidArgumentException
* @since 9.0.0
*/
public function setQuota($quota) {
$oldQuota = $this->config->getUserValue($this->uid, 'files', 'quota', '');
if ($quota !== 'none' and $quota !== 'default') {
$quota = OC_Helper::computerFileSize($quota);
$quota = OC_Helper::humanFileSize((int)$quota);
$bytesQuota = OC_Helper::computerFileSize($quota);
if ($bytesQuota === false) {
throw new InvalidArgumentException('Failed to set quota to invalid value '.$quota);
}
$quota = OC_Helper::humanFileSize($bytesQuota);
}
if ($quota !== $oldQuota) {
$this->config->setUserValue($this->uid, 'files', 'quota', $quota);

@ -59,14 +59,11 @@ class OC_Files {
public const UPLOAD_MIN_LIMIT_BYTES = 1048576; // 1 MiB
private static $multipartBoundary = '';
private static string $multipartBoundary = '';
/**
* @return string
*/
private static function getBoundary() {
private static function getBoundary(): string {
if (empty(self::$multipartBoundary)) {
self::$multipartBoundary = md5(mt_rand());
self::$multipartBoundary = md5((string)mt_rand());
}
return self::$multipartBoundary;
}
@ -76,7 +73,7 @@ class OC_Files {
* @param string $name
* @param array $rangeArray ('from'=>int,'to'=>int), ...
*/
private static function sendHeaders($filename, $name, array $rangeArray) {
private static function sendHeaders($filename, $name, array $rangeArray): void {
OC_Response::setContentDispositionHeader($name, 'attachment');
header('Content-Transfer-Encoding: binary', true);
header('Pragma: public');// enable caching in IE
@ -247,10 +244,10 @@ class OC_Files {
/**
* @param string $rangeHeaderPos
* @param int $fileSize
* @param int|float $fileSize
* @return array $rangeArray ('from'=>int,'to'=>int), ...
*/
private static function parseHttpRangeHeader($rangeHeaderPos, $fileSize) {
private static function parseHttpRangeHeader($rangeHeaderPos, $fileSize): array {
$rArray = explode(',', $rangeHeaderPos);
$minOffset = 0;
$ind = 0;

@ -49,6 +49,7 @@ use OCP\Files\Mount\IMountPoint;
use OCP\ICacheFactory;
use OCP\IBinaryFinder;
use OCP\IUser;
use OCP\Util;
use Psr\Log\LoggerInterface;
/**
@ -59,12 +60,12 @@ class OC_Helper {
/**
* Make a human file size
* @param int $bytes file size in bytes
* @param int|float $bytes file size in bytes
* @return string a human readable file size
*
* Makes 2048 to 2 kB.
*/
public static function humanFileSize($bytes) {
public static function humanFileSize(int|float $bytes): string {
if ($bytes < 0) {
return "?";
}
@ -95,16 +96,16 @@ class OC_Helper {
/**
* Make a computer file size
* @param string $str file size in human readable format
* @return int|false a file size in bytes
* @return false|int|float a file size in bytes
*
* Makes 2kB to 2048.
*
* Inspired by: https://www.php.net/manual/en/function.filesize.php#92418
*/
public static function computerFileSize($str) {
public static function computerFileSize(string $str): false|int|float {
$str = strtolower($str);
if (is_numeric($str)) {
return (int)$str;
return Util::numericToNumber($str);
}
$bytes_array = [
@ -129,16 +130,14 @@ class OC_Helper {
return false;
}
$bytes = round($bytes);
return (int)$bytes;
return Util::numericToNumber(round($bytes));
}
/**
* Recursive copying of folders
* @param string $src source folder
* @param string $dest target folder
*
* @return void
*/
public static function copyr($src, $dest) {
if (is_dir($src)) {
@ -387,8 +386,8 @@ class OC_Helper {
* calculates the maximum upload size respecting system settings, free space and user quota
*
* @param string $dir the current folder where the user currently operates
* @param int $freeSpace the number of bytes free on the storage holding $dir, if not set this will be received from the storage directly
* @return int number of bytes representing
* @param int|float $freeSpace the number of bytes free on the storage holding $dir, if not set this will be received from the storage directly
* @return int|float number of bytes representing
*/
public static function maxUploadFilesize($dir, $freeSpace = null) {
if (is_null($freeSpace) || $freeSpace < 0) {
@ -401,7 +400,7 @@ class OC_Helper {
* Calculate free space left within user quota
*
* @param string $dir the current folder where the user currently operates
* @return int number of bytes representing
* @return int|float number of bytes representing
*/
public static function freeSpace($dir) {
$freeSpace = \OC\Files\Filesystem::free_space($dir);
@ -416,12 +415,12 @@ class OC_Helper {
/**
* Calculate PHP upload limit
*
* @return int PHP upload file size limit
* @return int|float PHP upload file size limit
*/
public static function uploadLimit() {
$ini = \OC::$server->get(IniGetWrapper::class);
$upload_max_filesize = (int)OCP\Util::computerFileSize($ini->get('upload_max_filesize'));
$post_max_size = (int)OCP\Util::computerFileSize($ini->get('post_max_size'));
$upload_max_filesize = Util::computerFileSize($ini->get('upload_max_filesize')) ?: 0;
$post_max_size = Util::computerFileSize($ini->get('post_max_size')) ?: 0;
if ($upload_max_filesize === 0 && $post_max_size === 0) {
return INF;
} elseif ($upload_max_filesize === 0 || $post_max_size === 0) {
@ -582,7 +581,7 @@ class OC_Helper {
/**
* Get storage info including all mount points and quota
*/
private static function getGlobalStorageInfo(int $quota, IUser $user, IMountPoint $mount): array {
private static function getGlobalStorageInfo(int|float $quota, IUser $user, IMountPoint $mount): array {
$rootInfo = \OC\Files\Filesystem::getFileInfo('', 'ext');
$used = $rootInfo['size'];
if ($used < 0) {

@ -52,6 +52,19 @@ class OC_Response {
* @param string|int|float $length Length to be sent
*/
public static function setContentLengthHeader($length) {
if (PHP_INT_SIZE === 4) {
if ($length > PHP_INT_MAX && stripos(PHP_SAPI, 'apache') === 0) {
// Apache PHP SAPI casts Content-Length headers to PHP integers.
// This enforces a limit of PHP_INT_MAX (2147483647 on 32-bit
// platforms). So, if the length is greater than PHP_INT_MAX,
// we just do not send a Content-Length header to prevent
// bodies from being received incompletely.
return;
}
// Convert signed integer or float to unsigned base-10 string.
$lfh = new \OC\LargeFileHelper;
$length = $lfh->formatUnsignedInteger($length);
}
header('Content-Length: '.$length);
}

@ -146,7 +146,7 @@ class OC_Util {
/**
* check if share API enforces a default expire date
*
* @return boolean
* @return bool
* @suppress PhanDeprecatedFunction
*/
public static function isDefaultExpireDateEnforced() {
@ -159,7 +159,7 @@ class OC_Util {
* Get the quota of a user
*
* @param IUser|null $user
* @return int|\OCP\Files\FileInfo::SPACE_UNLIMITED|false Quota bytes
* @return int|\OCP\Files\FileInfo::SPACE_UNLIMITED|false|float Quota bytes
*/
public static function getUserQuota(?IUser $user) {
if (is_null($user)) {

@ -84,7 +84,7 @@ interface FileInfo {
* Get the size in bytes for the file or folder
*
* @param bool $includeMounts whether or not to include the size of any sub mounts, since 16.0.0
* @return int
* @return int|float
* @since 7.0.0
*/
public function getSize($includeMounts = true);

@ -145,7 +145,7 @@ interface Node extends FileInfo {
* Get the size of the file or folder in bytes
*
* @param bool $includeMounts
* @return int
* @return int|float
* @throws InvalidPathException
* @throws NotFoundException
* @since 6.0.0

@ -49,7 +49,7 @@ interface ISimpleFile {
*
* @since 11.0.0
*/
public function getSize(): int;
public function getSize(): int|float;
/**
* Get the ETag

@ -68,7 +68,7 @@ class InMemoryFile implements ISimpleFile {
* @inheritdoc
* @since 16.0.0
*/
public function getSize(): int {
public function getSize(): int|float {
return strlen($this->contents);
}

@ -135,7 +135,7 @@ interface Storage extends IStorage {
* The result for filesize when called on a folder is required to be 0
*
* @param string $path
* @return int|bool
* @return false|int|float
* @since 6.0.0
*/
public function filesize($path);

@ -132,7 +132,7 @@ interface IStorage {
* The result for filesize when called on a folder is required to be 0
*
* @param string $path
* @return int|bool
* @return false|int|float
* @since 9.0.0
*/
public function filesize($path);

@ -339,25 +339,36 @@ class Util {
return $user_part.'@localhost.localdomain';
}
/**
* Converts string to int of float depending if it fits an int
* @param numeric-string|float|int $number numeric string
* @return int|float int if it fits, float if it is too big
* @since 26.0.0
*/
public static function numericToNumber(string|float|int $number): int|float {
/* This is a hack to cast to (int|float) */
return 0 + (string)$number;
}
/**
* Make a human file size (2048 to 2 kB)
* @param int $bytes file size in bytes
* @param int|float $bytes file size in bytes
* @return string a human readable file size
* @since 4.0.0
*/
public static function humanFileSize($bytes) {
public static function humanFileSize(int|float $bytes): string {
return \OC_Helper::humanFileSize($bytes);
}
/**
* Make a computer file size (2 kB to 2048)
* @param string $str file size in a fancy format
* @return float|false a file size in bytes
* @return false|int|float a file size in bytes
*
* Inspired by: https://www.php.net/manual/en/function.filesize.php#92418
* @since 4.0.0
*/
public static function computerFileSize($str) {
public static function computerFileSize(string $str): false|int|float {
return \OC_Helper::computerFileSize($str);
}
@ -474,31 +485,31 @@ class Util {
* calculates the maximum upload size respecting system settings, free space and user quota
*
* @param string $dir the current folder where the user currently operates
* @param int $free the number of bytes free on the storage holding $dir, if not set this will be received from the storage directly
* @return int number of bytes representing
* @param int|float|null $free the number of bytes free on the storage holding $dir, if not set this will be received from the storage directly
* @return int|float number of bytes representing
* @since 5.0.0
*/
public static function maxUploadFilesize($dir, $free = null) {
public static function maxUploadFilesize(string $dir, int|float|null $free = null): int|float {
return \OC_Helper::maxUploadFilesize($dir, $free);
}
/**
* Calculate free space left within user quota
* @param string $dir the current folder where the user currently operates
* @return int number of bytes representing
* @return int|float number of bytes representing
* @since 7.0.0
*/
public static function freeSpace($dir) {
public static function freeSpace(string $dir): int|float {
return \OC_Helper::freeSpace($dir);
}
/**
* Calculate PHP upload limit
*
* @return int number of bytes representing
* @return int|float number of bytes representing
* @since 7.0.0
*/
public static function uploadLimit() {
public static function uploadLimit(): int|float {
return \OC_Helper::uploadLimit();
}

@ -1798,7 +1798,18 @@ class ViewTest extends \Test\TestCase {
['is_file', ['dir'], 'dir', null],
['stat', ['dir'], 'dir', null],
['filetype', ['dir'], 'dir', null],
['filesize', ['dir'], 'dir', null],
[
'filesize',
['dir'],
'dir',
null,
ILockingProvider::LOCK_SHARED,
ILockingProvider::LOCK_SHARED,
ILockingProvider::LOCK_SHARED,
null,
/* Return an int */
100
],
['isCreatable', ['dir'], 'dir', null],
['isReadable', ['dir'], 'dir', null],
['isUpdatable', ['dir'], 'dir', null],
@ -1832,7 +1843,8 @@ class ViewTest extends \Test\TestCase {
$expectedLockBefore = ILockingProvider::LOCK_SHARED,
$expectedLockDuring = ILockingProvider::LOCK_SHARED,
$expectedLockAfter = ILockingProvider::LOCK_SHARED,
$expectedStrayLock = null
$expectedStrayLock = null,
$returnValue = true,
) {
$view = new View('/' . $this->user . '/files/');
@ -1853,10 +1865,10 @@ class ViewTest extends \Test\TestCase {
$storage->expects($this->once())
->method($operation)
->willReturnCallback(
function () use ($view, $lockedPath, &$lockTypeDuring) {
function () use ($view, $lockedPath, &$lockTypeDuring, $returnValue) {
$lockTypeDuring = $this->getFileLockType($view, $lockedPath);
return true;
return $returnValue;
}
);

@ -9,6 +9,10 @@
namespace Test\Memcache;
/**
* @group Memcache
* @group APCu
*/
class APCuTest extends Cache {
protected function setUp(): void {
parent::setUp();

@ -9,6 +9,9 @@
namespace Test\Memcache;
/**
* @group Memcache
*/
class ArrayCacheTest extends Cache {
protected function setUp(): void {
parent::setUp();

@ -23,6 +23,9 @@ namespace Test\Memcache;
use Test\TestCase;
/**
* @group Memcache
*/
class CasTraitTest extends TestCase {
/**
* @return \OC\Memcache\CasTrait

@ -61,6 +61,9 @@ class Test_Factory_Unavailable_Cache2 extends NullCache {
}
}
/**
* @group Memcache
*/
class FactoryTest extends \Test\TestCase {
public const AVAILABLE1 = '\\Test\\Memcache\\Test_Factory_Available_Cache1';
public const AVAILABLE2 = '\\Test\\Memcache\\Test_Factory_Available_Cache2';

@ -9,6 +9,10 @@
namespace Test\Memcache;
/**
* @group Memcache
* @group Memcached
*/
class MemcachedTest extends Cache {
public static function setUpBeforeClass(): void {
parent::setUpBeforeClass();

@ -9,6 +9,10 @@
namespace Test\Memcache;
/**
* @group Memcache
* @group Redis
*/
class RedisTest extends Cache {
public static function setUpBeforeClass(): void {
parent::setUpBeforeClass();

@ -71,10 +71,10 @@ class MemoryInfoTest extends TestCase {
* Tests that getMemoryLimit works as expected.
*
* @param string $iniValue The "memory_limit" ini data.
* @param int $expected The expected detected memory limit.
* @param int|float $expected The expected detected memory limit.
* @dataProvider getMemoryLimitTestData
*/
public function testMemoryLimit($iniValue, int $expected) {
public function testMemoryLimit(string $iniValue, int|float $expected) {
ini_set('memory_limit', $iniValue);
$memoryInfo = new MemoryInfo();
self::assertEquals($expected, $memoryInfo->getMemoryLimit());

@ -30,12 +30,20 @@ use Test\TestCase;
/**
* Class RouterTest
*
* @group RoutingWeirdness
*
* @package Test\Route
*/
class RouterTest extends TestCase {
public function testGenerateConsecutively(): void {
/** @var LoggerInterface $logger */
$logger = $this->createMock(LoggerInterface::class);
$logger->method('info')
->willReturnCallback(
function (string $message, array $data) {
$this->fail('Unexpected info log: '.(string)($data['exception'] ?? $message));
}
);
$router = new Router($logger);
$this->assertEquals('/index.php/apps/files/', $router->generate('files.view.index'));