summaryrefslogtreecommitdiffstats
path: root/includes/utilities.inc
blob: 0eee637c5a4845d5bffc71c2990183b2e91deacd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
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
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
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
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
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
<?php

/**
 * @file
 * Utility and wrapper functions for the advagg module.
 */

/**
 * Given path output uri to that file
 */
function advagg_build_uri($path) {
  static $hook_file_url_alter = array();

  // If the current path is an absolute path, return immediately.
  $fragments = parse_url($path);
  if (isset($fragments['host'])) {
    return $path;
  }

  $original_path = $path;
  // CDN Support.
  if (module_exists('cdn')) {
    $status = variable_get(CDN_STATUS_VARIABLE, CDN_DISABLED);
    if ($status == CDN_ENABLED || ($status == CDN_TESTING && user_access(CDN_PERM_ACCESS_TESTING))) {
      // Alter URL when the file_create_url() patch is not there.
      if (variable_get(CDN_THEME_LAYER_FALLBACK_VARIABLE, FALSE)) {
        cdn_file_url_alter($path);
      }
      // Use the patched version of file_create_url().
      else {
        $path = file_create_url($path);
      }
      // Return here if the path was changed above.
      if (strcmp($original_path, $path) != 0) {
        return $path;
      }
    }
  }

  // Other modules besides CDN might want to use hook_file_url_alter.
  if (empty($hook_file_url_alter)) {
    $hook_file_url_alter = module_implements('file_url_alter');
  }
  if (!empty($hook_file_url_alter)) {
    $path = file_create_url($path);
    // Return here if the path was changed above.
    if (strcmp($original_path, $path) != 0) {
      return $path;
    }
  }

  // If nothing was altered then use the drupal default.
  return base_path() . $path;
}

/**
 * Helper function to build an URL for asynchronous requests.
 *
 * @param $filepath
 *   Path to a URI excluding everything to the left and including the base path.
 */
function _advagg_build_url($filepath = '') {
  global $base_path;

  // Server auth.
  $auth = '';
  if (isset($_SERVER['AUTH_TYPE']) && $_SERVER['AUTH_TYPE'] == 'Basic') {
    $auth = $_SERVER['PHP_AUTH_USER'] . ':' . $_SERVER['PHP_AUTH_PW'] . '@';
  }

  // Host.
  $ip = variable_get('advagg_server_addr', FALSE);
  if ($ip == -1) {
    $ip = $_SERVER['HTTP_HOST'];
  }
  elseif (empty($ip)) {
    $ip = empty($_SERVER['SERVER_ADDR']) ? '127.0.0.1' : $_SERVER['SERVER_ADDR'];
  }

  // Port.
  $port = '';
//   if (   isset($_SERVER['SERVER_PORT'])
//       && is_numeric($_SERVER['SERVER_PORT'])
//       && ($_SERVER['SERVER_PORT'] != 80 || $_SERVER['SERVER_PORT'] != 443)
//         ) {
//     $port = ':' . $_SERVER['SERVER_PORT'];
//   }
  return 'http://' . $auth . $ip . $port . $base_path . $filepath;
}

/**
 * Wrapper around clearstatcache so it can use php 5.3's new features.
 *
 * @param $clear_realpath_cache
 *   Bool.
 * @param $filename
 *   String.
 * @return
 *   value from clearstatcache().
 */
function advagg_clearstatcache($clear_realpath_cache = FALSE, $filename = NULL) {
  static $php530;
  if (!isset($php530)) {
    $php530 = version_compare(PHP_VERSION, '5.3.0', '>=');
  }

  if ($php530) {
    return clearstatcache($clear_realpath_cache, $filename);
  }
  else {
    return clearstatcache();
  }
}

/**
 * Helper function to determine if the cookie to bypass aggregation is active.
 *
 * @return bool
 *   TRUE if enabled, FALSE otherwise.
 */
function advagg_cookie_bypass() {
  return !empty($_COOKIE[ADVAGG_COOKIE_NAME]) && $_COOKIE[ADVAGG_COOKIE_NAME] === md5(drupal_get_private_key()) ? TRUE : FALSE;
}

/**
 * Select records in the database matching where IN(...).
 *
 * NOTE Be aware of the servers max_packet_size variable.
 *
 * @param $table
 *   The name of the table.
 * @param $field
 *  field name to be compared to
 * @param $placeholder
 *   db_query placeholders; like %d or '%s'
 * @param $data
 *   array of values you wish to compare to
 * @param $returns
 *   array of db fields you return
 * @return
 *   returns db_query() result.
 */
function advagg_db_multi_select_in($table, $field, $placeholder, $data, $returns = array(), $groupby = '') {
  // Set returns if empty
  if (empty($returns)) {
    $returns[] = '*';
  }
  // Get the number of rows that will be inserted
  $rows = count($data);
  // Create what goes in the IN ()
  $in = $placeholder;
  // Add the rest of the place holders
  for ($i = 1; $i < $rows; $i++) {
    $in .= ', ' . $placeholder;
  }
  // Build the query
  $query = "SELECT " . implode(', ', $returns) . " FROM {" . $table . "} WHERE $field IN ($in) $groupby";
  // Run the query
  // TODO Please convert this statement to the D7 database API syntax.
  return db_query($query, $data);
}

/**
 * Get the CSS & JS path for advagg.
 *
 * @return
 *   Example below:
 *   array(
 *     array(
 *       public://advagg_css,
 *       sites/default/files/advagg_css,
 *     ),
 *     array(
 *       public://advagg_js,
 *       sites/default/files/advagg_js,
 *     ),
 *   )
 */
function advagg_get_root_files_dir() {
  static $css_path;
  static $js_path;
  // Make sure directories are available and writable.
  if (empty($css_path) || empty($js_path)) {
    $css_path = 'public://advagg_css';
    $js_path = 'public://advagg_js';
    file_prepare_directory($css_path, FILE_CREATE_DIRECTORY);
    file_prepare_directory($js_path, FILE_CREATE_DIRECTORY);
    $css_path = parse_url(file_create_url($css_path));
    $js_path = parse_url(file_create_url($js_path));
  }
  return array(ltrim($css_path['path'], '/'), ltrim($js_path['path'], '/'));
}

/**
 * Return the server schema (http or https).
 *
 * @return string
 *   http OR https.
 * @TODO: We probably should use relative references instead of trying to
 *        determine it based on the $_SERVER array.
 * @see: http://tools.ietf.org/html/rfc3986#section-4.2
 * @see: http://paulirish.com/2010/the-protocol-relative-url
 * @see: http://www.stevesouders.com/blog/2010/02/10/5a-missing-schema-double-download/
 */
function advagg_get_server_schema() {
  return (   (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on')
          || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
          || (isset($_SERVER['HTTP_HTTPS']) && $_SERVER['HTTP_HTTPS'] == 'on')
            ) ? 'https' : 'http';
}

/**
 * Always return TRUE, used for array_map in advagg_css_js_file_builder().
 */
function advagg_return_true() {
  return TRUE;
}

/**
 * See if a string ends with a substring.
 *
 * @param $haystack
 *   The main string being compared.
 * @param $needle
 *   The secondary string being compared.
 * @return
 *   bool
 */
function advagg_string_ends_with($haystack, $needle) {
  // Define substr_compare if it doesn't exist (PHP 4 fix).
  if (!function_exists('substr_compare')) {
    /**
     * Binary safe comparison of two strings from an offset, up to length
     * characters.
     *
     * Compares main_str from position offset with str up to length characters.
     * @see http://php.net/substr-compare#53084
     *
     * @param $main_str
     *   The main string being compared.
     * @param $str
     *   The secondary string being compared.
     * @param $offset
     *   The start position for the comparison. If negative, it starts counting
     *   from the end of the string.
     * @param $length
     *   The length of the comparison. The default value is the largest of the
     *   length of the str compared to the length of main_str less the offset.
     * @param $case_insensitivity
     *   If TRUE, comparison is case insensitive.
     * @return
     *   Returns < 0 if main_str from position offset is less than str, > 0 if
     *   it is greater than str, and 0 if they are equal. If offset is equal to
     *   or greater than the length of main_str or length is set and is less than
     *   1, substr_compare() prints a warning and returns FALSE.
     */
    function substr_compare($main_str, $str, $offset, $length = NULL, $case_insensitivity = FALSE) {
      $offset = (int) $offset;

      // Throw a warning because the offset is invalid
      if ($offset >= strlen($main_str)) {
        trigger_error('The start position cannot exceed initial string length.', E_USER_WARNING);
        return FALSE;
      }

      // We are comparing the first n-characters of each string, so let's use the PHP function to do it
      if ($offset == 0 && is_int($length) && $case_insensitivity === TRUE) {
        return strncasecmp($main_str, $str, $length);
      }

      // Get the substring that we are comparing
      if (is_int($length)) {
        $main_substr = substr($main_str, $offset, $length);
        $str_substr = substr($str, 0, $length);
      }
      else {
        $main_substr = substr($main_str, $offset);
        $str_substr = $str;
      }

      // Return a case-insensitive comparison of the two strings
      if ($case_insensitivity === TRUE) {
        return strcasecmp($main_substr, $str_substr);
      }

      // Return a case-sensitive comparison of the two strings
      return strcmp($main_substr, $str_substr);
    }
  }

  $haystack_len = strlen($haystack);
  $needle_len = strlen($needle);
  if ($needle_len > $haystack_len) {
    return FALSE;
  }
  return substr_compare($haystack, $needle, $haystack_len -$needle_len, $needle_len, TRUE) === 0;
}

if (!function_exists('array_merge_recursive_distinct')) {
  /**
  * Merges any number of arrays / parameters recursively, replacing
  * entries with string keys with values from latter arrays.
  * If the entry or the next value to be assigned is an array, then it
  * automagically treats both arguments as an array.
  * Numeric entries are appended, not replaced, but only if they are
  * unique
  *
  * calling: result = array_merge_recursive_distinct(a1, a2, ... aN)
 **/

 function array_merge_recursive_distinct () {
   $arrays = func_get_args();
   $base = array_shift($arrays);
   if(!is_array($base)) $base = empty($base) ? array() : array($base);
   foreach($arrays as $append) {
     if(!is_array($append)) $append = array($append);
     foreach($append as $key => $value) {
       if(!array_key_exists($key, $base) and !is_numeric($key)) {
         $base[$key] = $append[$key];
         continue;
       }
       if(is_array($value) or is_array($base[$key])) {
         $base[$key] = array_merge_recursive_distinct($base[$key], $append[$key]);
       } else if(is_numeric($key)) {
         if(!in_array($value, $base)) $base[] = $value;
       } else {
         $base[$key] = $value;
       }
     }
   }
   return $base;
 }
}