(dev/core#1044) Extension/MIME matching should be case insensitive
[civicrm-core.git] / CRM / Core / Page / File.php
index e3b12d2a9289adebb569e7f0cb79a49ef232c17b..8c35a9fc07c8255076d925e55f3def1d1406e1e2 100644 (file)
@@ -42,9 +42,12 @@ class CRM_Core_Page_File extends CRM_Core_Page {
     $download = CRM_Utils_Request::retrieve('download', 'Integer', $this, FALSE, 1);
     $disposition = $download == 0 ? 'inline' : 'download';
 
-    $entityId = CRM_Utils_Request::retrieve('eid', 'Positive', $this, FALSE); // Entity ID (e.g. Contact ID)
-    $fieldId = CRM_Utils_Request::retrieve('fid', 'Positive', $this, FALSE); // Field ID
-    $fileId = CRM_Utils_Request::retrieve('id', 'Positive', $this, FALSE); // File ID
+    // Entity ID (e.g. Contact ID)
+    $entityId = CRM_Utils_Request::retrieve('eid', 'Positive', $this, FALSE);
+    // Field ID
+    $fieldId = CRM_Utils_Request::retrieve('fid', 'Positive', $this, FALSE);
+    // File ID
+    $fileId = CRM_Utils_Request::retrieve('id', 'Positive', $this, FALSE);
     $fileName = CRM_Utils_Request::retrieve('filename', 'String', $this, FALSE);
     if (empty($fileName) && (empty($entityId) || empty($fileId))) {
       CRM_Core_Error::statusBounce("Cannot access file: Must pass either \"Filename\" or the combination of \"Entity ID\" + \"File ID\"");
@@ -65,12 +68,25 @@ class CRM_Core_Page_File extends CRM_Core_Page {
       $mimeType = '';
       $path = CRM_Core_Config::singleton()->customFileUploadDir . $fileName;
     }
-    $mimeType = CRM_Utils_Request::retrieveValue('mime-type', 'String', $mimeType, FALSE);
 
     if (!$path) {
       CRM_Core_Error::statusBounce('Could not retrieve the file');
     }
 
+    if (empty($mimeType)) {
+      $passedInMimeType = self::convertBadMimeAliasTypes(CRM_Utils_Request::retrieveValue('mime-type', 'String', $mimeType, FALSE));
+      if (!in_array($passedInMimeType, explode(',', Civi::settings()->get('requestableMimeTypes')))) {
+        throw new CRM_Core_Exception("Supplied mime-type is not accepted");
+      }
+      $extension = CRM_Utils_File::getExtensionFromPath($path);
+      $candidateExtensions = CRM_Utils_File::getAcceptableExtensionsForMimeType($passedInMimeType);
+      if (!in_array(strtolower($extension), array_map('strtolower', $candidateExtensions))) {
+        throw new CRM_Core_Exception("Supplied mime-type does not match file extension");
+      }
+      // Now that we have validated mime-type supplied as much as possible lets now set the MimeType variable/
+      $mimeType = $passedInMimeType;
+    }
+
     $buffer = file_get_contents($path);
     if (!$buffer) {
       CRM_Core_Error::statusBounce('The file is either empty or you do not have permission to retrieve the file');
@@ -98,4 +114,33 @@ class CRM_Core_Page_File extends CRM_Core_Page {
     }
   }
 
+  /**
+   * Translate one mime type to another.
+   *
+   * Certain non-standard/weird MIME types have been common. Unfortunately, because
+   * of the way this controller is used, the weird types may baked-into URLs.
+   * We clean these up for compatibility.
+   *
+   * @param string $type
+   *   Ex: 'image/jpg'
+   * @return string
+   *   Ex: 'image/jpeg'.
+   */
+  protected static function convertBadMimeAliasTypes($type) {
+    $badTypes = [
+      // Before PNG format was ubiquitous, it was image/x-png?
+      'image/x-png' => 'image/png',
+
+      // People see "image/gif" and "image/png" and wrongly guess "image/jpg"?
+      'image/jpg' => 'image/jpeg',
+      'image/tif' => 'image/tiff',
+      'image/svg' => 'image/svg+xml',
+
+      // StackExchange attributes "pjpeg" to some quirk in an old version of IE?
+      'image/pjpeg' => 'image/jpeg',
+
+    ];
+    return isset($badTypes[$type]) ? $badTypes[$type] : $type;
+  }
+
 }