diff --git a/docs/channels/entries.md b/docs/channels/entries.md index d84d40ca7..0fd0be80f 100755 --- a/docs/channels/entries.md +++ b/docs/channels/entries.md @@ -277,7 +277,7 @@ You can hard code the channel tag to show a specific channel entry. You may also entry_id="13|42|147" -Or use "not" to exclude entries:: +Or use "not" to exclude entries: entry_id="not 45|534|807" @@ -311,7 +311,7 @@ NOTE: **Note:** Using this parameter will automatically constrain the entries ta ### `group_id=` -NOTE: We recommend using [primary_role_id=](#primary_role_id) parameter instead, which works the same but more clearly conveys that the filtering is happening on primary role ID. +NOTE: We recommend using the [primary_role_id=](#primary_role_id) parameter instead, which works the same but more clearly conveys that the filtering is happening on primary role ID. group_id="4" @@ -319,7 +319,7 @@ You can decide from which Member Role (by specifying the role ID) you wish entri group_id="2|3|4" -Or exclude role using "not" +Or exclude roles using "not" group_id="not 2|3|4" @@ -368,10 +368,14 @@ The `orderby` parameter sets the display order of the entries. Setting options f - `orderby="view_count_three"` - `orderby="view_count_four"` -In addition you can order by a [channel field](control-panel/field-manager/field-manager-settings.md). Use the "short_name" of the field: +In addition, you can order by a [channel field](control-panel/field-manager/field-manager-settings.md). Use the "short_name" of the field: orderby="name_of_field" +You can also order results by file names: + + orderby="file_field:filename" + NOTE: **Note:** Ordering by a Relationship field will cause entries to appear in the order the relationships were made, not based on any content from the related entries. NOTE: **Note:** **Random** ordered entries have special rules applied. "Sticky" entries will not appear first; they will appear randomly with all other entries. If the tag is not paginated, each page load, a new selection of random entries will be returned. If the tag **is** paginated, then the order of the entries is randomly set on the first page load and stored for the user's session so that entries show up only once in the paginated results. @@ -398,17 +402,17 @@ Will result in: Default Site - Entry One - Albert Default Site - Entry Two - Bobby - Second Site  - Entry One - Alligator - Second Site  - Entry Two - Buffalo + Second Site - Entry One - Alligator + Second Site - Entry Two - Buffalo If you have multiple Sites where each site has a field with the same exact short name, then you can specify that short name (without the site specified) and ExpressionEngine will treat those two fields as the same value and be able to order them as if they were the same field: orderby="body" Default Site - Entry One - Albert - Second Site  - Entry One - Alligator + Second Site - Entry One - Alligator Default Site - Entry Two - Bobby - Second Site  - Entry Two - Buffalo + Second Site - Entry Two - Buffalo Thus, the output will then be ordered by the body, regardless of the originating site. @@ -570,7 +574,7 @@ This example would return all results where the body field is empty. search:body="not IS_EMPTY" -This example would return all results where the body field is **not** empty, i.e. only entries where the body field had content. +This example would return all results where the body field is **not** empty, i.e., only entries where the body field had content. The IS_EMPTY search constant can also be used in conjunction with other search terms, for both "Exact" and "Contains" type matching. @@ -590,13 +594,13 @@ NOTE: **Note:** You may use multiple search: parameters in a channel entries tag {exp:channel:entries search:style="=ale" search:region="germany|belgium" search:rating="=3|4|5"} -When using multiple search parameters, all search parameters must be matched in order for an entry to be included. The above example would pull back only those entries where the style is 'ale', the region is 'germany' or 'belgium' and the rating is 1, 2 or 3. +When using multiple search parameters, all search parameters must be matched in order for an entry to be included. The above example would pull back only those entries where the style is 'ale', the region is 'germany' or 'belgium', and the rating is 3, 4, or 5. ### `show_current_week=` show_current_week="yes" -Requires use of the [display_by=](#display_by) "week" parameter. When set to "yes", it displays the current week by default (i.e. no pagination in the URL) and automatically adjusts the pagination links to indicate the correct page for that week. +Requires use of the [display_by=](#display_by) "week" parameter. When set to "yes", it displays the current week by default (i.e., no pagination in the URL) and automatically adjusts the pagination links to indicate the correct page for that week. ### `show_expired=` @@ -739,7 +743,7 @@ This parameter limits the query by username. You can use the pipe character to q username="tom|dick|harry" -Or you can add "not" to exclude usernames +Or you can add "not" to exclude usernames: username="not tom|dick|harry|fred" @@ -747,7 +751,7 @@ You can also use the token `"CURRENT_USER"` to show entries from only the curren username="CURRENT_USER" -This allow each logged-in user to get only their entries. Users who are not logged in won't see anything. Alternatively, you can use the token `"NOT_CURRENT_USER"` to show entries **except** from the currently logged in user. +This allows each logged-in user to get only their entries. Users who are not logged in won't see anything. Alternatively, you can use the token `"NOT_CURRENT_USER"` to show entries **except** from the currently logged-in user. username="NOT_CURRENT_USER" @@ -791,7 +795,7 @@ If five entries are being displayed per page, then for the fourth entry on the s ### `{absolute_index}` -Similar to `absolute_count` but starts at 0 instead of 1. So the first entry will have value of "0" and the second entry will have a value of "1" etc. +Similar to `absolute_count` but starts at 0 instead of 1. So the first entry will have a value of "0" and the second entry will have a value of "1", etc. ### `{absolute_results}` @@ -839,7 +843,7 @@ The name of the channel that the currently displayed entry is assigned to. ### `{channel_id}` -The ID number of the actual channel (not the _entry_.) +The ID number of the actual channel (not the _entry_). ### `{channel_short_name}` @@ -969,7 +973,7 @@ The date on which the entry was last edited in GMT. This variable is **not** loc ### `{index}` -Similar to `count` but starts at 0 instead of 1. So the first entry will have value of "0" and the second entry will have a value of "1" etc. +Similar to `count` but starts at 0 instead of 1. So the first entry will have a value of "0" and the second entry will have a value of "1", etc. ### `{ip_address}` @@ -985,13 +989,13 @@ This variable is replaced by a URL that passes the author's member name to your ### `{page_uri}` -If you have the Pages Module installed and if you have associated a static page with a channel entry (via the "Pages" section of the Publish tab), this is the page uri for the page. It will typically be used like so: +If you have the Pages Module installed and if you have associated a static page with a channel entry (via the "Pages" section of the Publish tab), this is the page URI for the page. It will typically be used like so: {if page_uri != ''} View this page {/if} ### `{page_url}` -If you have the Pages Module installed and if you have associated a static page with a channel entry (via the "Pages" section of the Publish tab), this is the page url for the page (the site URL + the page URI). It will typically be used like so: +If you have the Pages Module installed and if you have associated a static page with a channel entry (via the "Pages" section of the Publish tab), this is the page URL for the page (the site URL + the page URI). It will typically be used like so: {if page_url != ''} View this page {/if} @@ -1071,7 +1075,7 @@ The width of the signature image associated with the entry's author. Typically u ### `{status}` -The status of the entry (open, closed, etc.) +The status of the entry (open, closed, etc.). ### `{switch}` @@ -1156,19 +1160,19 @@ Conditionals allow you to more precisely control your content. NOTE: **Note:** A more complete explanation of conditional control structures and operators can be found on the [Conditional Tags](templates/conditionals.md) page. -Here is an example that tests for the "summary" field being not empty +Here is an example that tests for the "summary" field being not empty: {if summary != ""} The summary is not empty! {/if} -An alternate, shorthand syntax can accomplish the same thing +An alternate, shorthand syntax can accomplish the same thing: {if summary} The summary is not empty! {/if} -If only the variable name is in the conditional statement it tests for "not empty". +If only the variable name is in the conditional statement, it tests for "not empty". Many of the single variables can be used in a conditional. You may always use the short name of one of your custom entry fields in a conditional. In addition, there are several unique conditionals. @@ -1250,7 +1254,7 @@ Lastly, if you want to simply display your 404 page (with 404 headers) when no e NOTE: **Note:** If you have several nested tags, each one would need to include a `{if no_results}` pair to be parsed correctly. -For instance, if you have Grid field with `{if no_results}` block, the parent `{exp:channel:entries}` tag pair would need to include `{if no_results}` block as well. +For instance, if you have a Grid field with an `{if no_results}` block, the parent `{exp:channel:entries}` tag pair would need to include an `{if no_results}` block as well: ``` {exp:channel:entries channel="blog"} {if no_results} No entries {/if} @@ -1297,13 +1301,13 @@ You may test whether an entry is set to be "sticky". You may also test whether i [TOC=3] -Variable pairs contain an opening and closing tag as well as content in-between. Example: +Variable pairs contain an opening and closing tag as well as content in between. Example: {date_heading}

{entry_date format="%Y %m %d"}

{/date_heading} The reason variable pairs have an opening and closing pair is because the information between the pairs can be shown or not shown if the criteria for each tag is met. -In the case of the "date_heading" pair, for example, it only appears at a certain interval that you set (hourly, daily, weekly, monthly, etc.). By using a pair of variables you can put HTML formatting between them that only gets shown when the interval is met. Otherwise, the chunk is not displayed. +In the case of the "date_heading" pair, for example, it only appears at a certain interval that you set (hourly, daily, weekly, monthly, etc.). By using a pair of variables, you can put HTML formatting between them that only gets shown when the interval is met. Otherwise, the chunk is not displayed. ### `{date_footer}` @@ -1462,9 +1466,9 @@ The category ID associated with the category's parent (or 0 in the case of a top {path='channel/index'} -This variable will be replaced by a URL to the specifies Template Group/Template. The category designation information will automatically be added to the end of the URL so that the target page will know which category to display. +This variable will be replaced by a URL to the specified Template Group/Template. The category designation information will automatically be added to the end of the URL so that the target page will know which category to display. -If you want the category links to point to your site index instead of a particular template group/template you can use SITE_INDEX instead: +If you want the category links to point to your site index instead of a particular template group/template, you can use SITE_INDEX instead: {categories} {category_name} {/categories} diff --git a/docs/development/services/mime.md b/docs/development/services/mime.md new file mode 100644 index 000000000..3a9924839 --- /dev/null +++ b/docs/development/services/mime.md @@ -0,0 +1,209 @@ +--- +lang: php +--- + + +# MimeType Service + +[TOC] + +The `MimeType` service in ExpressionEngine provides a robust way to detect and validate MIME types of files and data buffers. This service is essential for ensuring that uploaded files are of the expected type and safe for processing. It includes functionality to manage a whitelist of allowed MIME types, detect MIME types from files or buffers, and perform specific checks like determining if a file is an image. + +## Overview + +The `MimeType` class allows developers to: +- Detect MIME types of files and data buffers. +- Validate MIME types against a configurable whitelist. +- Check if a file is an image or safe for upload. +- Extend the whitelist with custom MIME types. + +This service is particularly useful for handling file uploads securely and ensuring compliance with content policies by restricting file types. + +## Usage Examples + +Here are some common use cases for the `MimeType` service: + +### Detecting MIME Type of a File + +To determine the MIME type of a file at a given path: + + $mime = ee('MimeType')->ofFile($path); + echo $mime; // Outputs something like 'image/jpeg' or 'application/pdf' + +### Detecting MIME Type of a Data Buffer + +To determine the MIME type of raw data: + + $data = file_get_contents($path); + $mime = ee('MimeType')->ofBuffer($data); + echo $mime; // Outputs the MIME type based on the buffer content + +### Guessing MIME Type for Octet Stream + +When a file is detected as a generic `application/octet-stream`, you can attempt to guess a more specific type: + + $opening = file_get_contents($path, false, null, 0, 50); + $mime = ee('MimeType')->guessOctetStream($opening); + echo $mime; // Might output 'image/webp' or 'application/pdf' if identifiable + +### Checking if a MIME Type Matches a Specific Kind + +To check if a MIME type belongs to a specific category or kind: + + $filePath = '/path/to/file'; + $allowed_type = 'image'; + if (ee('MimeType')->isOfKind(ee('MimeType')->ofFile($filePath), $allowed_type)) { + echo 'This file is of the allowed type.'; + } + +### Validating if a File is Safe for Upload + +To ensure a file's MIME type is in the whitelist and safe for upload: + + $path = '/path/to/uploaded/file'; + if (ee('MimeType')->fileIsSafeForUpload($path)) { + echo 'This file is safe to upload.'; + } else { + echo 'This file type is not allowed.'; + } + +### Checking if a MIME Type is Safe for Upload + +To check a specific MIME type against the whitelist: + + $mime = 'image/png'; + $safeForUpload = ee('MimeType')->isSafeForUpload($mime) ? $mime : false; + if ($safeForUpload) { + echo 'This MIME type is safe for upload.'; + } + +### Checking if a File is an Image + +To determine if a file is an image based on its MIME type and content: + + $path = '/path/to/file'; + if (ee('MimeType')->fileIsImage($path)) { + echo 'This file is an image.'; + } + +## MimeType Methods + +**class `ExpressionEngine\Library\Mime\MimeType`** + +[TOC=3] + +### `addMimeType($mime, $kind = null)` + +Adds a single MIME type to the whitelist. + +| Parameter | Type | Description | +| --------- | -------- | ------------------------------------- | +| \$mime | `String` | The MIME type to add | +| \$kind | `String` | Optional category or kind of MIME type| +| Returns | `Void` | | + +### `addMimeTypes(array $mimes, $kind = null)` + +Adds multiple MIME types to the whitelist. + +| Parameter | Type | Description | +| --------- | -------- | ------------------------------------- | +| \$mimes | `Array` | An array of MIME types to add | +| \$kind | `String` | Optional category or kind of MIME type| +| Returns | `Void` | | + +### `getWhitelist()` + +Returns the current whitelist of MIME types. + +| Parameter | Type | Description | +| --------- | ------- | ------------------------------------- | +| Returns | `Array` | An array of whitelisted MIME types | + +### `isOfKind($mime, $mimeTypeKind)` + +Checks if a MIME type belongs to a specific kind or category. + +| Parameter | Type | Description | +| --------------- | -------- | ------------------------------------- | +| \$mime | `String` | The MIME type to check | +| \$mimeTypeKind | `String` | The kind or category to check against | +| Returns | `Boolean`| TRUE if it matches the kind, FALSE otherwise | + +### `ofFile($path)` + +Determines the MIME type of a file. + +| Parameter | Type | Description | +| --------- | -------- | ------------------------------------- | +| \$path | `String` | The full path to the file | +| Returns | `String` | The MIME type of the file | + +### `ofBuffer($buffer)` + +Determines the MIME type of a data buffer. + +| Parameter | Type | Description | +| --------- | -------- | ------------------------------------- | +| \$buffer | `String` | The data buffer to check | +| Returns | `String` | The MIME type of the buffer | + +### `guessOctetStream($contents)` + +Attempts to guess a more specific MIME type for data identified as `application/octet-stream`. + +| Parameter | Type | Description | +| ----------- | -------- | ------------------------------------- | +| \$contents | `String` | The content to analyze | +| Returns | `String` | The guessed MIME type | + +### `fileIsImage($path)` + +Determines if a file is an image. + +| Parameter | Type | Description | +| --------- | -------- | ------------------------------------- | +| \$path | `String` | The full path to the file | +| Returns | `Boolean`| TRUE if it is an image, FALSE otherwise | + +### `isImage($mime)` + +Checks if a MIME type is recognized as an image type. + +| Parameter | Type | Description | +| --------- | -------- | ------------------------------------- | +| \$mime | `String` | The MIME type to check | +| Returns | `Boolean`| TRUE if it is an image type, FALSE otherwise | + +### `fileIsSafeForUpload($path)` + +Checks if a file's MIME type is safe for upload based on the whitelist. + +| Parameter | Type | Description | +| --------- | -------- | ------------------------------------- | +| \$path | `String` | The full path to the file | +| Returns | `Boolean`| TRUE if safe for upload, FALSE otherwise | + +### `isSafeForUpload($mime)` + +Checks if a specific MIME type is safe for upload based on the whitelist. + +| Parameter | Type | Description | +| --------- | -------- | ------------------------------------- | +| \$mime | `String` | The MIME type to check | +| Returns | `Boolean`| TRUE if safe for upload, FALSE otherwise | + +### `whitelistMimesFromConfig()` + +Loads MIME types from configuration files into the whitelist, including any additional MIME types specified in the configuration. + +| Parameter | Type | Description | +| --------- | ------- | ------------------------------------- | +| Returns | `Void` | | diff --git a/docs/toc_sections/_advanced_usage_toc.yml b/docs/toc_sections/_advanced_usage_toc.yml index a4bae53f1..b20f45120 100644 --- a/docs/toc_sections/_advanced_usage_toc.yml +++ b/docs/toc_sections/_advanced_usage_toc.yml @@ -338,6 +338,8 @@ href: development/services/encrypt.md - name: Event Service href: development/services/event.md + - name: MimeType Service + href: development/services/mime.md - name: CP/FilePicker Service href: development/services/filepicker.md - name: CP/Filter Service