Returns and optionally sets the filename for a system resource.
The filename, whether provided, cached, or retrieved from the database, is only returned if the file exists.
This function plays a key role in allowing Drupal's resources (modules and themes) to be located in different places depending on a site's configuration. For example, a module 'foo' may legally be be located in any of these three places:
core/modules/foo/foo.module modules/foo/foo.module sites/example.com/modules/foo/foo.module
Calling drupal_get_filename('module', 'foo') will give you one of the above, depending on where the module is located.
$type: The type of the item (i.e. theme, theme_engine, module, profile).
$name: The name of the item for which the filename is requested.
$filename: The filename of the item if it is to be set explicitly rather than by consulting the database.
The filename of the requested item.
function drupal_get_filename($type, $name, $filename = NULL) {
// The location of files will not change during the request, so do not use
// drupal_static().
static $files = array(), $dirs = array();
// Profiles are converted into modules in system_rebuild_module_data().
// @todo Remove false-exposure of profiles as modules.
$original_type = $type;
if ($type == 'profile') {
$type = 'module';
}
if (!isset($files[$type])) {
$files[$type] = array();
}
if (!empty($filename) && file_exists($filename)) {
$files[$type][$name] = $filename;
}
elseif (isset($files[$type][$name])) {
// nothing
}
else {
// Verify that we have an keyvalue service before using it. This is required
// because this function is called during installation.
// @todo Inject database connection into KeyValueStore\DatabaseStorage.
if (drupal_container()
->has('keyvalue') && function_exists('db_query')) {
try {
$file_list = state()
->get('system.' . $type . '.files');
if ($file_list && isset($file_list[$name]) && file_exists(DRUPAL_ROOT . '/' . $file_list[$name])) {
$files[$type][$name] = $file_list[$name];
}
} catch (Exception $e) {
// The keyvalue service raised an exception because the backend might
// be down. We have a fallback for this case so we hide the error
// completely.
}
}
// Fallback to searching the filesystem if the database could not find the
// file or the file returned by the database is not found.
if (!isset($files[$type][$name])) {
// We have consistent directory naming: modules, themes...
$dir = $type . 's';
if ($type == 'theme_engine') {
$dir = 'themes/engines';
$extension = 'engine';
}
elseif ($type == 'theme') {
$extension = 'info';
}
elseif ($original_type == 'profile') {
$dir = 'profiles';
$extension = 'profile';
}
else {
$extension = $type;
}
if (!isset($dirs[$dir][$extension])) {
$dirs[$dir][$extension] = TRUE;
if (!function_exists('drupal_system_listing')) {
require_once DRUPAL_ROOT . '/core/includes/common.inc';
}
// Scan the appropriate directories for all files with the requested
// extension, not just the file we are currently looking for. This
// prevents unnecessary scans from being repeated when this function is
// called more than once in the same page request.
$matches = drupal_system_listing("/^" . DRUPAL_PHP_FUNCTION_PATTERN . "\\.{$extension}\$/", $dir);
foreach ($matches as $matched_name => $file) {
$files[$type][$matched_name] = $file->uri;
}
}
}
}
if (isset($files[$type][$name])) {
return $files[$type][$name];
}
}