diff --git a/composer/Plugin/Scaffold/ManageGitIgnore.php b/composer/Plugin/Scaffold/ManageGitIgnore.php index 078cb335786..6f2eb09fb00 100644 --- a/composer/Plugin/Scaffold/ManageGitIgnore.php +++ b/composer/Plugin/Scaffold/ManageGitIgnore.php @@ -115,7 +115,7 @@ class ManageGitIgnore { // Appending to existing .gitignore files. if (file_exists($git_ignore_path)) { $contents = file_get_contents($git_ignore_path); - if (!empty($contents) && substr($contents, -1) != "\n") { + if (!empty($contents) && !str_ends_with($contents, "\n")) { $contents .= "\n"; } } diff --git a/core/includes/errors.inc b/core/includes/errors.inc index 9820f9fe2ac..6ec930dd346 100644 --- a/core/includes/errors.inc +++ b/core/includes/errors.inc @@ -67,7 +67,7 @@ function _drupal_error_handler_real($error_level, $message, $filename, $line) { // As __toString() methods must not throw exceptions (recoverable errors) // in PHP, we allow them to trigger a fatal error by emitting a user error // using trigger_error(). - $to_string = $error_level == E_USER_ERROR && substr($caller['function'], -strlen('__toString()')) == '__toString()'; + $to_string = $error_level == E_USER_ERROR && str_ends_with($caller['function'], '__toString()'); _drupal_log_error([ '%type' => isset($types[$error_level]) ? $severity_msg : 'Unknown error', // The standard PHP error handler considers that the error messages diff --git a/core/lib/Drupal/Component/PhpStorage/MTimeProtectedFastFileStorage.php b/core/lib/Drupal/Component/PhpStorage/MTimeProtectedFastFileStorage.php index be287f99bfc..415079376fb 100644 --- a/core/lib/Drupal/Component/PhpStorage/MTimeProtectedFastFileStorage.php +++ b/core/lib/Drupal/Component/PhpStorage/MTimeProtectedFastFileStorage.php @@ -200,7 +200,7 @@ class MTimeProtectedFastFileStorage extends FileStorage { // file. Thus, when switching between MTimeProtectedFastFileStorage and // FileStorage, the subdirectory or the file cannot be created in case the // other file type exists already. - if (substr($name, -4) === '.php') { + if (str_ends_with($name, '.php')) { $name = substr($name, 0, -4); } return $this->directory . '/' . str_replace('/', '#', $name); diff --git a/core/lib/Drupal/Core/Command/DbImportCommand.php b/core/lib/Drupal/Core/Command/DbImportCommand.php index cf461df7346..6da8b5739d1 100644 --- a/core/lib/Drupal/Core/Command/DbImportCommand.php +++ b/core/lib/Drupal/Core/Command/DbImportCommand.php @@ -56,7 +56,7 @@ class DbImportCommand extends DbCommandBase { protected function runScript(Connection $connection, $script) { $old_key = Database::setActiveConnection($connection->getKey()); - if (substr($script, -3) == '.gz') { + if (str_ends_with($script, '.gz')) { $script = "compress.zlib://$script"; } try { diff --git a/core/lib/Drupal/Core/Config/Entity/Query/QueryFactory.php b/core/lib/Drupal/Core/Config/Entity/Query/QueryFactory.php index 3322287c6e2..064e5b4e9f5 100644 --- a/core/lib/Drupal/Core/Config/Entity/Query/QueryFactory.php +++ b/core/lib/Drupal/Core/Config/Entity/Query/QueryFactory.php @@ -162,7 +162,7 @@ class QueryFactory implements QueryFactoryInterface, EventSubscriberInterface { * you cannot do fast lookups against this. */ protected function getKeys(Config $config, $key, $get_method, ConfigEntityTypeInterface $entity_type) { - if (substr($key, -1) == '*') { + if (str_ends_with($key, '*')) { throw new InvalidLookupKeyException(strtr('%entity_type lookup key %key ends with a wildcard this can not be used as a lookup', ['%entity_type' => $entity_type->id(), '%key' => $key])); } $parts = explode('.*', $key); diff --git a/core/lib/Drupal/Core/Database/Connection.php b/core/lib/Drupal/Core/Database/Connection.php index cdaf0d19ddd..9f98b00a278 100644 --- a/core/lib/Drupal/Core/Database/Connection.php +++ b/core/lib/Drupal/Core/Database/Connection.php @@ -886,7 +886,7 @@ abstract class Connection { // If the placeholder indicated the value to use is an array, we need to // expand it out into a comma-delimited set of placeholders. foreach ($args as $key => $data) { - $is_bracket_placeholder = substr($key, -2) === '[]'; + $is_bracket_placeholder = str_ends_with($key, '[]'); $is_array_data = is_array($data); if ($is_bracket_placeholder && !$is_array_data) { throw new \InvalidArgumentException('Placeholders with a trailing [] can only be expanded with an array of values.'); diff --git a/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php b/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php index f42b6115f8a..d165ace48a8 100644 --- a/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php +++ b/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php @@ -484,7 +484,7 @@ class YamlFileLoader $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; } - if ('=' === substr($value, -1)) { + if (str_ends_with($value, '=')) { $value = substr($value, 0, -1); } diff --git a/core/lib/Drupal/Core/Entity/EntityLastInstalledSchemaRepository.php b/core/lib/Drupal/Core/Entity/EntityLastInstalledSchemaRepository.php index 1b3c096126c..9f75e2d9aa9 100644 --- a/core/lib/Drupal/Core/Entity/EntityLastInstalledSchemaRepository.php +++ b/core/lib/Drupal/Core/Entity/EntityLastInstalledSchemaRepository.php @@ -69,7 +69,7 @@ class EntityLastInstalledSchemaRepository implements EntityLastInstalledSchemaRe // Filter out field storage definitions. $filtered_keys = array_filter(array_keys($all_definitions), function ($key) { - return substr($key, -12) === '.entity_type'; + return str_ends_with($key, '.entity_type'); }); $entity_type_definitions = array_intersect_key($all_definitions, array_flip($filtered_keys)); diff --git a/core/lib/Drupal/Core/Entity/Query/Sql/QueryAggregate.php b/core/lib/Drupal/Core/Entity/Query/Sql/QueryAggregate.php index 3e3cb1e62dc..fd257ab6939 100644 --- a/core/lib/Drupal/Core/Entity/Query/Sql/QueryAggregate.php +++ b/core/lib/Drupal/Core/Entity/Query/Sql/QueryAggregate.php @@ -154,7 +154,7 @@ class QueryAggregate extends Query implements QueryAggregateInterface { public function createSqlAlias($field, $sql_field) { $alias = str_replace('.', '_', $sql_field); // If the alias contains of field_*_value remove the _value at the end. - if (str_starts_with($alias, 'field_') && substr($field, -6) !== '_value' && substr($alias, -6) === '_value') { + if (str_starts_with($alias, 'field_') && !str_ends_with($field, '_value') && str_ends_with($alias, '_value')) { $alias = substr($alias, 0, -6); } return $alias; diff --git a/core/lib/Drupal/Core/Extension/Discovery/RecursiveExtensionFilterIterator.php b/core/lib/Drupal/Core/Extension/Discovery/RecursiveExtensionFilterIterator.php index af8d2d464bf..f4964c94c38 100644 --- a/core/lib/Drupal/Core/Extension/Discovery/RecursiveExtensionFilterIterator.php +++ b/core/lib/Drupal/Core/Extension/Discovery/RecursiveExtensionFilterIterator.php @@ -156,14 +156,14 @@ class RecursiveExtensionFilterIterator extends \RecursiveFilterIterator { // config module to be overridden/replaced in a profile/site directory // (whereas it must be located directly in a modules directory). if ($name == 'config') { - return substr($this->current()->getPathname(), -14) == 'modules/config'; + return str_ends_with($this->current()->getPathname(), 'modules/config'); } // Accept the directory unless the folder is skipped. return !in_array($name, $this->skippedFolders, TRUE); } else { // Only accept extension info files. - return substr($name, -9) == '.info.yml'; + return str_ends_with($name, '.info.yml'); } } diff --git a/core/lib/Drupal/Core/Extension/ExtensionVersion.php b/core/lib/Drupal/Core/Extension/ExtensionVersion.php index a5c064b49f2..589774cfec3 100644 --- a/core/lib/Drupal/Core/Extension/ExtensionVersion.php +++ b/core/lib/Drupal/Core/Extension/ExtensionVersion.php @@ -119,7 +119,7 @@ final class ExtensionVersion { * The ExtensionVersion instance. */ public static function createFromSupportBranch(string $branch): ExtensionVersion { - if (substr($branch, -1) !== '.') { + if (!str_ends_with($branch, '.')) { throw new \UnexpectedValueException("Invalid support branch: $branch"); } return static::createFromVersionString($branch . '0'); diff --git a/core/lib/Drupal/Core/File/FileSystem.php b/core/lib/Drupal/Core/File/FileSystem.php index 9d1e66b4bd4..f88ba9d8f54 100644 --- a/core/lib/Drupal/Core/File/FileSystem.php +++ b/core/lib/Drupal/Core/File/FileSystem.php @@ -596,7 +596,7 @@ class FileSystem implements FileSystemInterface { } // A URI or path may already have a trailing slash or look like "public://". - if (substr($directory, -1) == '/') { + if (str_ends_with($directory, '/')) { $separator = ''; } else { @@ -711,7 +711,7 @@ class FileSystem implements FileSystemInterface { while (FALSE !== ($filename = readdir($handle))) { // Skip this file if it matches the nomask or starts with a dot. if ($filename[0] != '.' && !(preg_match($options['nomask'], $filename))) { - if (substr($dir, -1) == '/') { + if (str_ends_with($dir, '/')) { $uri = "$dir$filename"; } else { diff --git a/core/lib/Drupal/Core/FileTransfer/FileTransfer.php b/core/lib/Drupal/Core/FileTransfer/FileTransfer.php index 2724b0d792a..f22cfde5032 100644 --- a/core/lib/Drupal/Core/FileTransfer/FileTransfer.php +++ b/core/lib/Drupal/Core/FileTransfer/FileTransfer.php @@ -312,7 +312,7 @@ abstract class FileTransfer { public function sanitizePath($path) { // Windows path sanitization. $path = str_replace('\\', '/', $path); - if (substr($path, -1) == '/') { + if (str_ends_with($path, '/')) { $path = substr($path, 0, -1); } return $path; diff --git a/core/lib/Drupal/Core/Render/Element/ImageButton.php b/core/lib/Drupal/Core/Render/Element/ImageButton.php index 6f345ece40b..7289cadafc8 100644 --- a/core/lib/Drupal/Core/Render/Element/ImageButton.php +++ b/core/lib/Drupal/Core/Render/Element/ImageButton.php @@ -46,7 +46,7 @@ class ImageButton extends Submit { $input = $form_state->getUserInput(); foreach (explode('[', $element['#name']) as $element_name) { // chop off the ] that may exist. - if (substr($element_name, -1) == ']') { + if (str_ends_with($element_name, ']')) { $element_name = substr($element_name, 0, -1); } diff --git a/core/lib/Drupal/Core/Routing/UrlGenerator.php b/core/lib/Drupal/Core/Routing/UrlGenerator.php index e41fe77d407..d7d0a203217 100644 --- a/core/lib/Drupal/Core/Routing/UrlGenerator.php +++ b/core/lib/Drupal/Core/Routing/UrlGenerator.php @@ -321,10 +321,10 @@ class UrlGenerator implements UrlGeneratorInterface { // otherwise we would generate a URI that, when followed by a user agent // (e.g. browser), does not match this route $path = strtr($path, ['/../' => '/%2E%2E/', '/./' => '/%2E/']); - if ('/..' === substr($path, -3)) { + if (str_ends_with($path, '/..')) { $path = substr($path, 0, -2) . '%2E%2E'; } - elseif ('/.' === substr($path, -2)) { + elseif (str_ends_with($path, '/.')) { $path = substr($path, 0, -1) . '%2E'; } } diff --git a/core/lib/Drupal/Core/Test/TestDiscovery.php b/core/lib/Drupal/Core/Test/TestDiscovery.php index 9e394a4342e..d6e2336375f 100644 --- a/core/lib/Drupal/Core/Test/TestDiscovery.php +++ b/core/lib/Drupal/Core/Test/TestDiscovery.php @@ -273,10 +273,10 @@ class TestDiscovery { // We don't want to discover abstract TestBase classes, traits or // interfaces. They can be deprecated and will call @trigger_error() // during discovery. - return substr($file_name, -4) === '.php' && - substr($file_name, -12) !== 'TestBase.php' && - substr($file_name, -9) !== 'Trait.php' && - substr($file_name, -13) !== 'Interface.php'; + return str_ends_with($file_name, '.php') && + !str_ends_with($file_name, 'TestBase.php') && + !str_ends_with($file_name, 'Trait.php') && + !str_ends_with($file_name, 'Interface.php'); }); $files = new \RecursiveIteratorIterator($filter); $classes = []; diff --git a/core/lib/Drupal/Core/TypedData/DataReferenceDefinition.php b/core/lib/Drupal/Core/TypedData/DataReferenceDefinition.php index 3a2a66861c6..fc84856a276 100644 --- a/core/lib/Drupal/Core/TypedData/DataReferenceDefinition.php +++ b/core/lib/Drupal/Core/TypedData/DataReferenceDefinition.php @@ -35,7 +35,7 @@ class DataReferenceDefinition extends DataDefinition implements DataReferenceDef * {@inheritdoc} */ public static function createFromDataType($data_type) { - if (substr($data_type, -strlen('_reference')) != '_reference') { + if (!str_ends_with($data_type, '_reference')) { throw new \InvalidArgumentException('Data type must be of the form "{TARGET_TYPE}_reference"'); } // Cut of the _reference suffix. diff --git a/core/modules/file/src/Upload/FileUploadHandler.php b/core/modules/file/src/Upload/FileUploadHandler.php index a2c07911fdb..835c513e1ef 100644 --- a/core/modules/file/src/Upload/FileUploadHandler.php +++ b/core/modules/file/src/Upload/FileUploadHandler.php @@ -220,7 +220,7 @@ class FileUploadHandler { } // A file URI may already have a trailing slash or look like "public://". - if (substr($destination, -1) != '/') { + if (!str_ends_with($destination, '/')) { $destination .= '/'; } diff --git a/core/modules/filter/src/Plugin/Filter/FilterHtml.php b/core/modules/filter/src/Plugin/Filter/FilterHtml.php index 0718b73092e..b24aa06ab5a 100644 --- a/core/modules/filter/src/Plugin/Filter/FilterHtml.php +++ b/core/modules/filter/src/Plugin/Filter/FilterHtml.php @@ -124,7 +124,7 @@ class FilterHtml extends FilterBase { $allowed_attributes = ['exact' => [], 'prefix' => []]; foreach (($global_allowed_attributes + $tag_attributes) as $name => $values) { // A trailing * indicates wildcard, but it must have some prefix. - if (substr($name, -1) === '*' && $name[0] !== '*') { + if (str_ends_with($name, '*') && $name[0] !== '*') { $allowed_attributes['prefix'][str_replace('*', '', $name)] = $this->prepareAttributeValues($values); } else { @@ -231,7 +231,7 @@ class FilterHtml extends FilterBase { $result = ['exact' => [], 'prefix' => []]; foreach ($attribute_values as $name => $allowed) { // A trailing * indicates wildcard, but it must have some prefix. - if (substr($name, -1) === '*' && $name[0] !== '*') { + if (str_ends_with($name, '*') && $name[0] !== '*') { $result['prefix'][str_replace('*', '', $name)] = $allowed; } else { diff --git a/core/modules/jsonapi/src/Routing/Routes.php b/core/modules/jsonapi/src/Routing/Routes.php index f4766f5a875..6a3ab0d9064 100644 --- a/core/modules/jsonapi/src/Routing/Routes.php +++ b/core/modules/jsonapi/src/Routing/Routes.php @@ -87,7 +87,7 @@ class Routes implements ContainerInjectionInterface { sprintf('The provided base path should contain a leading slash "/". Given: "%s".', $jsonapi_base_path) ); assert( - substr($jsonapi_base_path, -1) !== '/', + !str_ends_with($jsonapi_base_path, '/'), sprintf('The provided base path should not contain a trailing slash "/". Given: "%s".', $jsonapi_base_path) ); $this->jsonApiBasePath = $jsonapi_base_path; diff --git a/core/modules/migrate/src/Plugin/migrate/process/FileCopy.php b/core/modules/migrate/src/Plugin/migrate/process/FileCopy.php index f4d006c0919..f7701ea27c5 100644 --- a/core/modules/migrate/src/Plugin/migrate/process/FileCopy.php +++ b/core/modules/migrate/src/Plugin/migrate/process/FileCopy.php @@ -210,7 +210,7 @@ class FileCopy extends FileProcessBase implements ContainerFactoryPluginInterfac */ protected function getDirectory($uri) { $dir = $this->fileSystem->dirname($uri); - if (substr($dir, -3) == '://') { + if (str_ends_with($dir, '://')) { return $this->fileSystem->realpath($dir); } return $dir; diff --git a/core/modules/migrate_drupal/tests/src/Kernel/MigrateDrupalTestBase.php b/core/modules/migrate_drupal/tests/src/Kernel/MigrateDrupalTestBase.php index 5cb4a954237..f7d3b0898f6 100644 --- a/core/modules/migrate_drupal/tests/src/Kernel/MigrateDrupalTestBase.php +++ b/core/modules/migrate_drupal/tests/src/Kernel/MigrateDrupalTestBase.php @@ -57,7 +57,7 @@ abstract class MigrateDrupalTestBase extends MigrateTestBase { $default_db = Database::getConnection()->getKey(); Database::setActiveConnection($this->sourceDatabase->getKey()); - if (substr($path, -3) == '.gz') { + if (str_ends_with($path, '.gz')) { $path = 'compress.zlib://' . $path; } require $path; diff --git a/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php index e9485aa3a73..f11e78c6d90 100644 --- a/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php +++ b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php @@ -82,7 +82,7 @@ abstract class MigrateUpgradeTestBase extends BrowserTestBase { $default_db = Database::getConnection()->getKey(); Database::setActiveConnection($this->sourceDatabase->getKey()); - if (substr($path, -3) == '.gz') { + if (str_ends_with($path, '.gz')) { $path = 'compress.zlib://' . $path; } require $path; diff --git a/core/tests/Drupal/BuildTests/Composer/Template/ComposerProjectTemplatesTest.php b/core/tests/Drupal/BuildTests/Composer/Template/ComposerProjectTemplatesTest.php index cfa493233af..dc0285bf9f1 100644 --- a/core/tests/Drupal/BuildTests/Composer/Template/ComposerProjectTemplatesTest.php +++ b/core/tests/Drupal/BuildTests/Composer/Template/ComposerProjectTemplatesTest.php @@ -425,7 +425,7 @@ JSON; // Strip off "-dev"; $version_towards = substr($version, 0, -4); - if (substr($version_towards, -2) !== '.0') { + if (!str_ends_with($version_towards, '.0')) { // If the current version is developing towards an x.y.z release where // z is not 0, it means that the x.y.0 has already been released, and // only stable changes are permitted on the branch. diff --git a/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php b/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php index 35ffe3ad464..1a57e5539a2 100644 --- a/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php +++ b/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php @@ -144,7 +144,7 @@ abstract class UpdatePathTestBase extends BrowserTestBase { // Load the database(s). foreach ($this->databaseDumpFiles as $file) { - if (substr($file, -3) == '.gz') { + if (str_ends_with($file, '.gz')) { $file = "compress.zlib://$file"; } require $file; diff --git a/core/tests/Drupal/Tests/Component/PhpStorage/MTimeProtectedFileStorageBase.php b/core/tests/Drupal/Tests/Component/PhpStorage/MTimeProtectedFileStorageBase.php index d38cdefba60..0056c4477cf 100644 --- a/core/tests/Drupal/Tests/Component/PhpStorage/MTimeProtectedFileStorageBase.php +++ b/core/tests/Drupal/Tests/Component/PhpStorage/MTimeProtectedFileStorageBase.php @@ -81,7 +81,7 @@ abstract class MTimeProtectedFileStorageBase extends PhpStorageTestBase { $name = 'test.php'; $php->save($name, 'directory . '/test'; - if (substr($name, -4) === '.php') { + if (str_ends_with($name, '.php')) { $expected_directory = $expected_root_directory . '/' . substr($name, 0, -4); } else {