Merge pull request #18069 from civicrm/5.28
[civicrm-core.git] / CRM / Utils / File.php
index 3ad79207b6711b83df29cfa8e54449c9c3f6b2a2..67da4b10a665daa9c2402aad61e81b434eeffd3b 100644 (file)
@@ -334,7 +334,7 @@ class CRM_Utils_File {
     if (CRM_Utils_Constant::value('CIVICRM_MYSQL_STRICT', CRM_Utils_System::isDevelopment())) {
       $db->query('SET SESSION sql_mode = STRICT_TRANS_TABLES');
     }
-    $db->query('SET NAMES utf8');
+    $db->query('SET NAMES utf8mb4');
     $transactionId = CRM_Utils_Type::escape(CRM_Utils_Request::id(), 'String');
     $db->query('SET @uniqueID = ' . "'$transactionId'");
 
@@ -753,9 +753,16 @@ HTACCESS;
    * @return array(string)
    */
   public static function findFiles($dir, $pattern, $relative = FALSE) {
-    if (!is_dir($dir)) {
+    if (!is_dir($dir) || !is_readable($dir)) {
       return [];
     }
+    // Which dirs should we exclude from our searches?
+    // If not defined, we default to excluding any dirname that begins
+    // with a . which is the old behaviour and therefore excludes .git/
+    $excludeDirsPattern = defined('CIVICRM_EXCLUDE_DIRS_PATTERN')
+      ? constant('CIVICRM_EXCLUDE_DIRS_PATTERN')
+      : '@' . preg_quote(DIRECTORY_SEPARATOR) . '\.@';
+
     $dir = rtrim($dir, '/');
     $todos = [$dir];
     $result = [];
@@ -769,13 +776,21 @@ HTACCESS;
           }
         }
       }
+      // Find subdirs to recurse into.
       if ($dh = opendir($subdir)) {
         while (FALSE !== ($entry = readdir($dh))) {
           $path = $subdir . DIRECTORY_SEPARATOR . $entry;
-          if ($entry{0} == '.') {
-            // ignore
-          }
-          elseif (is_dir($path)) {
+          // Exclude . (self) and .. (parent) to avoid infinite loop.
+          // Exclude configured exclude dirs.
+          // Exclude dirs we can't read.
+          // Exclude anything that's not a dir.
+          if (
+            $entry !== '.'
+            && $entry !== '..'
+            && (empty($excludeDirsPattern) || !preg_match($excludeDirsPattern, $path))
+            && is_dir($path)
+            && is_readable($path)
+          ) {
             $todos[] = $path;
           }
         }