path.inc 7.84 KB
Newer Older
1
<?php
2
3
4

/**
 * @file
5
 * Functions to handle paths in Drupal.
6
7
 *
 * These functions are not loaded for cached pages, but modules that need
8
9
 * to use them in hook exit() can make them available, by executing
 * "drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);".
10
11
 */

12
13
use Symfony\Component\HttpFoundation\Request;

14
15
16
17
18
19
20
/**
 * Check if the current page is the front page.
 *
 * @return
 *   Boolean value: TRUE if the current page is the front page; FALSE if otherwise.
 */
function drupal_is_front_page() {
21
  // Use the advanced drupal_static() pattern, since this is called very often.
22
23
24
25
26
  static $drupal_static_fast;
  if (!isset($drupal_static_fast)) {
    $drupal_static_fast['is_front_page'] = &drupal_static(__FUNCTION__);
  }
  $is_front_page = &$drupal_static_fast['is_front_page'];
27
28

  if (!isset($is_front_page)) {
29
    $is_front_page = (current_path() == config('system.site')->get('page.front'));
30
31
32
  }

  return $is_front_page;
33
}
34
35
36
37
38
39
40
41
42
43
44
45
46

/**
 * Check if a path matches any pattern in a set of patterns.
 *
 * @param $path
 *   The path to match.
 * @param $patterns
 *   String containing a set of patterns separated by \n, \r or \r\n.
 *
 * @return
 *   Boolean value: TRUE if the path matches a pattern, FALSE otherwise.
 */
function drupal_match_path($path, $patterns) {
47
  $regexps = &drupal_static(__FUNCTION__);
48

49
  if (!isset($regexps[$patterns])) {
50
51
52
53
54
55
56
57
58
59
    // Convert path settings to a regular expression.
    // Therefore replace newlines with a logical or, /* with asterisks and the <front> with the frontpage.
    $to_replace = array(
      '/(\r\n?|\n)/', // newlines
      '/\\\\\*/',     // asterisks
      '/(^|\|)\\\\<front\\\\>($|\|)/' // <front>
    );
    $replacements = array(
      '|',
      '.*',
60
      '\1' . preg_quote(config('system.site')->get('page.front'), '/') . '\2'
61
62
63
    );
    $patterns_quoted = preg_quote($patterns, '/');
    $regexps[$patterns] = '/^(' . preg_replace($to_replace, $replacements, $patterns_quoted) . ')$/';
64
  }
65
  return (bool)preg_match($regexps[$patterns], $path);
66
}
67
68
69
70
71
72
73
74
75
76
77

/**
 * Return the current URL path of the page being viewed.
 *
 * Examples:
 * - http://example.com/node/306 returns "node/306".
 * - http://example.com/drupalfolder/node/306 returns "node/306" while
 *   base_path() returns "/drupalfolder/".
 * - http://example.com/path/alias (which is a path alias for node/306) returns
 *   "node/306" as opposed to the path alias.
 *
78
 * This function is available only after DRUPAL_BOOTSTRAP_FULL.
79
80
81
 *
 * @return
 *   The current Drupal URL path.
82
83
 *
 * @see request_path()
84
85
 */
function current_path() {
86
87
88
  // @todo Remove the check for whether the request service exists and the
  // fallback code below, once the path alias logic has been figured out in
  // http://drupal.org/node/1269742.
89
  if (drupal_container()->isScopeActive('request')) {
90
91
92
93
    $path = drupal_container()->get('request')->attributes->get('system_path');
    if ($path !== NULL) {
      return $path;
    }
94
  }
95
96
  // If we are outside the request scope, fall back to using the path stored in
  // _current_path().
97
  return _current_path();
98
}
99

100
/**
101
 * Fetches a specific URL alias from the database.
102
103
104
105
106
 *
 * @param $conditions
 *   A string representing the source, a number representing the pid, or an
 *   array of query conditions.
 *
107
 * @see \Drupal\Core\Path\Path::load()
108
109
110
111
112
113
114
115
116
117
118
 */
function path_load($conditions) {
  if (is_numeric($conditions)) {
    $conditions = array('pid' => $conditions);
  }
  elseif (is_string($conditions)) {
    $conditions = array('source' => $conditions);
  }
  elseif (!is_array($conditions)) {
    return FALSE;
  }
119
  return drupal_container()->get('path.crud')->load($conditions);
120
121
}

122
/**
123
 * Determines whether a path is in the administrative section of the site.
124
 *
125
126
127
 * By default, paths are considered to be non-administrative. If a path does
 * not match any of the patterns in path_get_admin_paths(), or if it matches
 * both administrative and non-administrative patterns, it is considered
128
129
130
131
 * non-administrative.
 *
 * @param $path
 *   A Drupal path.
132
 *
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
 * @return
 *   TRUE if the path is administrative, FALSE otherwise.
 *
 * @see path_get_admin_paths()
 * @see hook_admin_paths()
 * @see hook_admin_paths_alter()
 */
function path_is_admin($path) {
  $path_map = &drupal_static(__FUNCTION__);
  if (!isset($path_map['admin'][$path])) {
    $patterns = path_get_admin_paths();
    $path_map['admin'][$path] = drupal_match_path($path, $patterns['admin']);
    $path_map['non_admin'][$path] = drupal_match_path($path, $patterns['non_admin']);
  }
  return $path_map['admin'][$path] && !$path_map['non_admin'][$path];
}

/**
151
 * Gets a list of administrative and non-administrative paths.
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
 *
 * @return array
 *   An associative array containing the following keys:
 *   'admin': An array of administrative paths and regular expressions
 *            in a format suitable for drupal_match_path().
 *   'non_admin': An array of non-administrative paths and regular expressions.
 *
 * @see hook_admin_paths()
 * @see hook_admin_paths_alter()
 */
function path_get_admin_paths() {
  $patterns = &drupal_static(__FUNCTION__);
  if (!isset($patterns)) {
    $paths = module_invoke_all('admin_paths');
    drupal_alter('admin_paths', $paths);
    // Combine all admin paths into one array, and likewise for non-admin paths,
    // for easier handling.
    $patterns = array();
    $patterns['admin'] = array();
    $patterns['non_admin'] = array();
    foreach ($paths as $path => $enabled) {
      if ($enabled) {
        $patterns['admin'][] = $path;
      }
      else {
        $patterns['non_admin'][] = $path;
      }
    }
    $patterns['admin'] = implode("\n", $patterns['admin']);
    $patterns['non_admin'] = implode("\n", $patterns['non_admin']);
  }
  return $patterns;
}
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213

/**
 * Checks a path exists and the current user has access to it.
 *
 * @param $path
 *   The path to check.
 * @param $dynamic_allowed
 *   Whether paths with menu wildcards (like user/%) should be allowed.
 *
 * @return
 *   TRUE if it is a valid path AND the current user has access permission,
 *   FALSE otherwise.
 */
function drupal_valid_path($path, $dynamic_allowed = FALSE) {
  global $menu_admin;
  // We indicate that a menu administrator is running the menu access check.
  $menu_admin = TRUE;
  if ($path == '<front>' || url_is_external($path)) {
    $item = array('access' => TRUE);
  }
  elseif ($dynamic_allowed && preg_match('/\/\%/', $path)) {
    // Path is dynamic (ie 'user/%'), so check directly against menu_router table.
    if ($item = db_query("SELECT * FROM {menu_router} where path = :path", array(':path' => $path))->fetchAssoc()) {
      $item['link_path']  = $form_item['link_path'];
      $item['link_title'] = $form_item['link_title'];
      $item['external']   = FALSE;
      $item['options'] = '';
      _menu_link_translate($item);
    }
214
215
216
217
    if (empty($item['access'])) {
      // Nothing was found in the old routing system, so try the new one.
      $item = _drupal_valid_path_new_router($path);
    }
218
219
220
  }
  else {
    $item = menu_get_item($path);
221
222
223
224
    if (empty($item['access'])) {
      // Nothing was found in the old routing system, so try the new one.
      $item = _drupal_valid_path_new_router($path);
    }
225
226
227
228
  }
  $menu_admin = FALSE;
  return $item && $item['access'];
}
229

230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
/**
 * Temporary helper function to check a path in the new routing system.
 *
 * @param string $path
 *   The path string as expected by drupal_valid_path().
 *
 * @return array|NULL
 *   An array containing 'access' => TRUE or NULL for paths that were not found
 *   or the user has no access to.
 */
function _drupal_valid_path_new_router($path) {
  $request = Request::create('/' . $path);
  $request->attributes->set('system_path', $path);
  try {
    $dc = drupal_container();
    $route = $dc->get('router.dynamic')->matchRequest($request);
    if (!empty($route)) {
      $dc->get('access_manager')->check($route['_route_object'], $request);
    }
    return array('access' => TRUE);
  }
  catch (Exception $e) {
    drupal_set_message($e->getMessage(), 'menu', WATCHDOG_ERROR);
  }
}