From 2985c7d3f2e1dadbb1b6237f83ff1d3afd673cbd Mon Sep 17 00:00:00 2001 From: David Gonzalez Date: Fri, 6 Jan 2017 14:17:03 +0100 Subject: [PATCH 1/8] [FilesCollection] Allow getFiles with dot syntax #112 --- system/HTTP/Files/FileCollection.php | 66 ++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 13 deletions(-) diff --git a/system/HTTP/Files/FileCollection.php b/system/HTTP/Files/FileCollection.php index 8aabd28205bd..910a15b9d6fc 100644 --- a/system/HTTP/Files/FileCollection.php +++ b/system/HTTP/Files/FileCollection.php @@ -82,19 +82,34 @@ public function all() */ public function getFile(string $name) { - $this->populateFiles(); - - $name = strtolower($name); - - if (array_key_exists($name, $this->files)) - { - return $this->files[$name]; - } - - return null; - } - - //-------------------------------------------------------------------- + $this->populateFiles(); + + $name = strtolower($name); + + if ($this->hasFile($name)) { + + if (strpos($name, '.') !== false) { + $name = explode('.', $name); + $uploadedFile = $this->getValueDotNotationSyntax($name, $this->files); + if($uploadedFile instanceof \CodeIgniter\HTTP\Files\UploadedFile){ + return $uploadedFile; + } + + return null; + } + + if (array_key_exists($name, $this->files)) { + return $this->files[$name]; + } + + return null; + + } + + return null; + } + + //-------------------------------------------------------------------- /** * Checks whether an uploaded file with name $fileID exists in @@ -250,4 +265,29 @@ protected function fixFilesArray(array $data): array } //-------------------------------------------------------------------- + + /** + * Navigate through a array looking for a particular index + * @param array $index The index sequence we are navigating down + * @param array $value The portion of the array to process + * @return mixed + */ + protected function getValueDotNotationSyntax($index, $value) { + if(is_array($index) && + count($index)) { + $current_index = array_shift($index); + } + if(is_array($index) && + count($index) && + is_array($value[$current_index]) && + count($value[$current_index])) { + return $this->getValueDotNotationSyntax($index, $value[$current_index]); + } else { + if(isset($value[$current_index])){ + return $value[$current_index]; + }else{ + return null; + } + } + } } From e91af29330b8650e17f13fa3379c75a52fba1cda Mon Sep 17 00:00:00 2001 From: David Gonzalez Date: Fri, 6 Jan 2017 22:12:57 +0100 Subject: [PATCH 2/8] Alway return a UploadedFile Instance --- system/HTTP/Files/FileCollection.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/system/HTTP/Files/FileCollection.php b/system/HTTP/Files/FileCollection.php index 910a15b9d6fc..983971a49ede 100644 --- a/system/HTTP/Files/FileCollection.php +++ b/system/HTTP/Files/FileCollection.php @@ -99,7 +99,12 @@ public function getFile(string $name) } if (array_key_exists($name, $this->files)) { - return $this->files[$name]; + $uploadedFile = $this->files[$name]; + if($uploadedFile instanceof \CodeIgniter\HTTP\Files\UploadedFile){ + return $uploadedFile; + } + + return null; } return null; From f50ef663e74c3aabe868383f9ab92b1085e3c8cb Mon Sep 17 00:00:00 2001 From: David Gonzalez Date: Fri, 6 Jan 2017 22:13:42 +0100 Subject: [PATCH 3/8] File Collection Unit testing --- .../system/HTTP/Files/FileCollectionTest.php | 123 +++++++++++++++++- 1 file changed, 122 insertions(+), 1 deletion(-) diff --git a/tests/system/HTTP/Files/FileCollectionTest.php b/tests/system/HTTP/Files/FileCollectionTest.php index 9e7e008d2033..be33803e24f9 100644 --- a/tests/system/HTTP/Files/FileCollectionTest.php +++ b/tests/system/HTTP/Files/FileCollectionTest.php @@ -255,7 +255,7 @@ public function testHasFileWithSingleFileNestedName() $this->assertTrue($collection->hasFile('userfile.foo')); $this->assertTrue($collection->hasFile('userfile.foo.bar')); } - + //-------------------------------------------------------------------- public function testErrorString() @@ -279,6 +279,127 @@ public function testErrorString() } //-------------------------------------------------------------------- + + public function testFileReturnsValidSingleFile() { + $_FILES = [ + 'userfile' => [ + 'name' => 'someFile.txt', + 'type' => 'text/plain', + 'size' => '124', + 'tmp_name' => '/tmp/myTempFile.txt', + 'error' => 0 + ] + ]; + + $collection = new FileCollection(); + $file = $collection->getFile('userfile'); + $this->assertTrue($file instanceof UploadedFile); + + $this->assertEquals('someFile.txt', $file->getName()); + $this->assertEquals(124, $file->getSize()); + } + + //-------------------------------------------------------------------- + + public function testFileNoExistSingleFile() { + $_FILES = [ + 'userfile' => [ + 'name' => 'someFile.txt', + 'type' => 'text/plain', + 'size' => '124', + 'tmp_name' => '/tmp/myTempFile.txt', + 'error' => 0 + ] + ]; + + $collection = new FileCollection(); + $file = $collection->getFile('fileuser'); + $this->AssertNull($file); + } + + //-------------------------------------------------------------------- + + public function testFileReturnValidMultipleFiles() { + $_FILES = [ + 'userfile' => [ + 'name' => ['fileA.txt', 'fileB.txt'], + 'type' => ['text/plain', 'text/csv'], + 'size' => ['124', '248'], + 'tmp_name' => ['/tmp/fileA.txt', '/tmp/fileB.txt'], + 'error' => 0 + ] + ]; + + $collection = new FileCollection(); + + $file_1 = $collection->getFile('userfile.0'); + $this->assertTrue($file_1 instanceof UploadedFile); + $this->assertEquals('fileA.txt', $file_1->getName()); + $this->assertEquals('/tmp/fileA.txt', $file_1->getTempName()); + $this->assertEquals('txt', $file_1->getClientExtension()); + $this->assertEquals('text/plain', $file_1->getClientType()); + $this->assertEquals(124, $file_1->getSize()); + + $file_2 = $collection->getFile('userfile.1'); + $this->assertTrue($file_2 instanceof UploadedFile); + $this->assertEquals('fileB.txt', $file_2->getName()); + $this->assertEquals('/tmp/fileB.txt', $file_2->getTempName()); + $this->assertEquals('txt', $file_2->getClientExtension()); + $this->assertEquals('text/csv', $file_2->getClientType()); + $this->assertEquals(248, $file_2->getSize()); + } + + //-------------------------------------------------------------------- + + public function testFileWithMultipleFilesNestedName() { + $_FILES = [ + 'my-form' => [ + 'name' => [ + 'details' => [ + 'avatars' => ['fileA.txt','fileB.txt'] + ] + ], + 'type' => [ + 'details' => [ + 'avatars' => ['text/plain','text/plain'] + ] + ], + 'size' => [ + 'details' => [ + 'avatars' => [125,243] + ] + ], + 'tmp_name' => [ + 'details' => [ + 'avatars' => ['/tmp/fileA.txt','/tmp/fileB.txt'] + ] + ], + 'error' => [ + 'details' => [ + 'avatars' => [0,0] + ] + ], + ] + ]; + + $collection = new FileCollection(); + + $file_1 = $collection->getFile('my-form.details.avatars.0'); + $this->assertTrue($file_1 instanceof UploadedFile); + $this->assertEquals('fileA.txt', $file_1->getName()); + $this->assertEquals('/tmp/fileA.txt', $file_1->getTempName()); + $this->assertEquals('txt', $file_1->getClientExtension()); + $this->assertEquals('text/plain', $file_1->getClientType()); + $this->assertEquals(125, $file_1->getSize()); + + $file_2 = $collection->getFile('my-form.details.avatars.1'); + $this->assertTrue($file_2 instanceof UploadedFile); + $this->assertEquals('fileB.txt', $file_2->getName()); + $this->assertEquals('/tmp/fileB.txt', $file_2->getTempName()); + $this->assertEquals('txt', $file_2->getClientExtension()); + $this->assertEquals('text/plain', $file_2->getClientType()); + $this->assertEquals(243, $file_2->getSize()); + } /** * @group move-file From 10ba45c62a1912f9b4f5ef27713b154c4335a988 Mon Sep 17 00:00:00 2001 From: David Gonzalez Date: Fri, 6 Jan 2017 22:18:35 +0100 Subject: [PATCH 4/8] User guide --- user_guide_src/source/libraries/uploaded_files.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/user_guide_src/source/libraries/uploaded_files.rst b/user_guide_src/source/libraries/uploaded_files.rst index b1eae323ffd2..c39f185ca845 100644 --- a/user_guide_src/source/libraries/uploaded_files.rst +++ b/user_guide_src/source/libraries/uploaded_files.rst @@ -69,9 +69,7 @@ In this case, the returned array of files would be more like:: If you just need to access a single file, you can use ``getFile()`` to retrieve the file instance directly:: - $file = $this->request->getFile('avatar'); - -.. note:: This currently only works with simple file names and not with array syntax naming. + $file = $this->request->getFile('my-form.details.avatar.0'); ===================== Working With the File From 0edbf4a3afc715768fd74c23010c15cf987f690f Mon Sep 17 00:00:00 2001 From: David Gonzalez Date: Sat, 7 Jan 2017 10:28:21 +0100 Subject: [PATCH 5/8] Some examples in the User Guide --- .../source/libraries/uploaded_files.rst | 54 ++++++++++++++++++- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/libraries/uploaded_files.rst b/user_guide_src/source/libraries/uploaded_files.rst index c39f185ca845..1839b1a3c9a7 100644 --- a/user_guide_src/source/libraries/uploaded_files.rst +++ b/user_guide_src/source/libraries/uploaded_files.rst @@ -15,6 +15,9 @@ array directly. Accessing Files =============== +All Files +---------- + When you upload files they can be accessed natively in PHP through the ``$_FILES`` superglobal. This array has some major shortcomings when working with multiple files uploaded at once, and has potential security flaws many developers are not aware of. CodeIgniter helps with both of these situations by standardizing your usage of files behind a @@ -67,9 +70,56 @@ In this case, the returned array of files would be more like:: ] ] -If you just need to access a single file, you can use ``getFile()`` to retrieve the file instance directly:: +Single File +---------- + +If you just need to access a single file, you can use ``getFile()`` to retrieve the file instance directly. This will return an instance of ``CodeIgniter\HTTP\Files\UploadedFile``: + +Simplest usage +^^^^^^^^^^ + +With the simplest usage, a single file might be submitted like:: + + + +Which would return a simple file instance like:: + + $file = $this->request->getFile('userfile'); + +Array Notation +^^^^^^^^^^ + +If you used an array notation for the name, the input would look something like:: + + + +For get the file instance:: + + $file = $this->request->getFile('my-form.details.avatar'); + + +Multiple files +^^^^^^^^^^ +If there are multiple files with the same name you can use ``getFile()`` ro retrieve every file individually:: + + + +In controller:: + + $file1 = $this->request->getFile('images.0'); + $file2 = $this->request->getFile('images.1'); + +Another example:: + + Upload an avatar: + Upload an avatar: + +In controller:: + + $file1 = $this->request->getFile('my-form.details.avatars.0'); + $file2 = $this->request->getFile('my-form.details.avatars.1'); - $file = $this->request->getFile('my-form.details.avatar.0'); +.. note:: For multiple files it is recommended to use the function ``getFiles()`` ===================== Working With the File From 478dd689b045b3d74b36956b98310e8445092cff Mon Sep 17 00:00:00 2001 From: David Gonzalez Date: Sat, 7 Jan 2017 10:34:24 +0100 Subject: [PATCH 6/8] User Guide. Fix Array notation syntax --- user_guide_src/source/libraries/uploaded_files.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/uploaded_files.rst b/user_guide_src/source/libraries/uploaded_files.rst index 1839b1a3c9a7..d2f0d4e77879 100644 --- a/user_guide_src/source/libraries/uploaded_files.rst +++ b/user_guide_src/source/libraries/uploaded_files.rst @@ -86,7 +86,7 @@ Which would return a simple file instance like:: $file = $this->request->getFile('userfile'); -Array Notation +Array notation ^^^^^^^^^^ If you used an array notation for the name, the input would look something like:: From fdb835a58735c2f1872a45fcbd651cd3347604c9 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 9 Jan 2017 21:17:15 +0700 Subject: [PATCH 7/8] Various typo fixes --- system/Database/BaseBuilder.php | 4 ++-- user_guide_src/source/database/migration.rst | 5 ++--- user_guide_src/source/database/query_builder.rst | 8 ++++---- user_guide_src/source/helpers/security_helper.rst | 2 +- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index edb5e088129f..bc5e165f08fc 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -1350,7 +1350,7 @@ public function getCompiledSelect($reset = true) * @param string the offset clause * @param bool If true, returns the generate SQL, otherwise executes the query. * - * @return CI_DB_result + * @return ResultInterface */ public function get($limit = null, $offset = null, $returnSQL = false) { @@ -1470,7 +1470,7 @@ public function countAllResults($reset = true, $test = false) * @param int $limit * @param int $offset * - * @return CI_DB_result + * @return ResultInterface */ public function getWhere($where = null, $limit = null, $offset = null) { diff --git a/user_guide_src/source/database/migration.rst b/user_guide_src/source/database/migration.rst index f87eaf6d9384..84cee5126df7 100644 --- a/user_guide_src/source/database/migration.rst +++ b/user_guide_src/source/database/migration.rst @@ -147,12 +147,12 @@ re-usable, modular code suites. Usage Example ************* -In this example some simple code is placed in **application/controllers/Migrate.php** +In this example some simple code is placed in **application/Controllers/Migrate.php** to update the schema:: setPath($path) ->latest(); - diff --git a/user_guide_src/source/database/query_builder.rst b/user_guide_src/source/database/query_builder.rst index 506fe978c463..061a2cb897f7 100644 --- a/user_guide_src/source/database/query_builder.rst +++ b/user_guide_src/source/database/query_builder.rst @@ -1009,8 +1009,8 @@ Class Reference :param int $limit: The LIMIT clause :param int $offset: The OFFSET clause - :returns: CI_DB_result instance (method chaining) - :rtype: CI_DB_result + :returns: \CodeIgniter\Database\ResultInterface instance (method chaining) + :rtype: \CodeIgniter\Database\ResultInterface Compiles and runs SELECT statement based on the already called Query Builder methods. @@ -1020,8 +1020,8 @@ Class Reference :param string $where: The WHERE clause :param int $limit: The LIMIT clause :param int $offset: The OFFSET clause - :returns: CI_DB_result instance (method chaining) - :rtype: CI_DB_result + :returns: \CodeIgniter\Database\ResultInterface instance (method chaining) + :rtype: \CodeIgniter\Database\ResultInterface Same as ``get()``, but also allows the WHERE to be added directly. diff --git a/user_guide_src/source/helpers/security_helper.rst b/user_guide_src/source/helpers/security_helper.rst index fc22fcdf0976..dce14425919e 100644 --- a/user_guide_src/source/helpers/security_helper.rst +++ b/user_guide_src/source/helpers/security_helper.rst @@ -27,7 +27,7 @@ The following functions are available: Provides protection against directory traversal. - This function is an alias for ``CI_Security::sanitize_filename()``. + This function is an alias for ``\CodeIgniter\Security::sanitize_filename()``. For more info, please see the :doc:`Security Library <../libraries/security>` documentation. From 820865f3e7414f052619e67f129cb42436caac0d Mon Sep 17 00:00:00 2001 From: Marlon Oliveira Date: Mon, 9 Jan 2017 19:00:30 -0200 Subject: [PATCH 8/8] Model::find(): Missing returnType when using array as parameter --- system/Model.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Model.php b/system/Model.php index 2c21e3d33c06..06488f1eef3f 100644 --- a/system/Model.php +++ b/system/Model.php @@ -287,7 +287,7 @@ public function find($id) { $row = $builder->whereIn($this->primaryKey, $id) ->get(); - $row = $row->getResult(); + $row = $row->getResult($this->tempReturnType); } else {