CRM_Utils_File::isChildPath - Fix checking of non-existent paths
authorTim Otten <totten@civicrm.org>
Wed, 10 Nov 2021 02:31:05 +0000 (18:31 -0800)
committerTim Otten <totten@civicrm.org>
Wed, 10 Nov 2021 02:50:23 +0000 (18:50 -0800)
Suppose you use call `isChildPath()` with these options:

* `$parent='/nonexistent'`
* `$child='/home/me/exists.txt'`
* `$checkRealPath=TRUE`

Before
=====

Reports that `/home/me/exists.txt` is a child of `/nonexistent`

After
=====

Reports that `/home/me/exists.txt` is NOT a child of `/nonexistent`

Comments
========

I added six test cases for how `isChildPath()` behaves when using
`$checkRealPath=TRUE`.  The first five cases behave the same with or without
the patch.  The patch fixes the last case.

CRM/Utils/File.php
tests/phpunit/CRM/Utils/FileTest.php

index 4fd3706bfa08e05e91b69546d0517a5db62aa13c..e4df98f11faeaa8365fc070a92b3903b25d89bc3 100644 (file)
@@ -802,6 +802,9 @@ HTACCESS;
     if ($checkRealPath) {
       $parent = realpath($parent);
       $child = realpath($child);
+      if ($parent === FALSE || $child === FALSE) {
+        return FALSE;
+      }
     }
     $parentParts = explode('/', rtrim($parent, '/'));
     $childParts = explode('/', rtrim($child, '/'));
index 94e26182284542c76b72000852384a9212006cf7..f475f927467742fea0aeadaa3456a6657ec975e4 100644 (file)
@@ -18,7 +18,22 @@ class CRM_Utils_FileTest extends CiviUnitTestCase {
     $testCases[] = ['/ab/cd', 'ab/cd/ef', FALSE];
     foreach ($testCases as $testCase) {
       $actual = CRM_Utils_File::isChildPath($testCase[0], $testCase[1], FALSE);
-      $this->assertEquals($testCase[2], $actual, sprintf("parent=[%s] child=[%s] expected=[%s] actual=[%s]",
+      $this->assertEquals($testCase[2], $actual, sprintf("parent=[%s] child=[%s] checkRealPath=[FALSE] expected=[%s] actual=[%s]",
+        $testCase[0], $testCase[1], $testCase[2], $actual
+      ));
+    }
+
+    global $civicrm_root;
+    $realCases = [];
+    $realCases[] = ["$civicrm_root", "$civicrm_root/CRM", TRUE];
+    $realCases[] = ["$civicrm_root/CRM", "$civicrm_root", FALSE];
+    $realCases[] = ["/nonexistent", "/nonexistent/child", FALSE];
+    $realCases[] = ["/nonexistent/child", "/nonexistent", FALSE];
+    $realCases[] = ["$civicrm_root", "/nonexistent", FALSE];
+    $realCases[] = ["/nonexistent", "$civicrm_root", FALSE];
+    foreach ($realCases as $testCase) {
+      $actual = CRM_Utils_File::isChildPath($testCase[0], $testCase[1], TRUE);
+      $this->assertEquals($testCase[2], $actual, sprintf("parent=[%s] child=[%s] checkRealPath=[TRUE] expected=[%s] actual=[%s]",
         $testCase[0], $testCase[1], $testCase[2], $actual
       ));
     }