1
2
3
4 """
5 Functions that need to be loaded on every Drupal requst
6
7 @package base.includes
8 @see <a href='http://drupy.net'>Drupy Homepage</a>
9 @see <a href='http://drupal.org'>Drupal Homepage</a>
10 @note Drupy is a port of the Drupal project.
11 @note This file was ported from Drupal's includes/bootstrap.inc
12 @author Brendon Crawford
13 @copyright 2008 Brendon Crawford
14 @contact message144 at users dot sourceforge dot net
15 @created 2008-01-10
16 @version 0.1
17 @note License:
18
19 This program is free software; you can redistribute it and/or
20 modify it under the terms of the GNU General Public License
21 as published by the Free Software Foundation; either version 2
22 of the License, or (at your option) any later version.
23
24 This program is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 GNU General Public License for more details.
28
29 You should have received a copy of the GNU General Public License
30 along with this program; if not, write to:
31
32 The Free Software Foundation, Inc.,
33 51 Franklin Street, Fifth Floor,
34 Boston, MA 02110-1301,
35 USA
36 """
37
38 __version__ = "$Revision: 1 $"
39
40
41
42
43 from lib.drupy import DrupyPHP as php
44 from lib.drupy import DrupyImport
45 from sites.default import settings
46 import appglobals as lib_appglobals
47 import cache as lib_cache
48 import database as lib_database
49 import session as lib_session
50 import theme_maintenance as lib_theme_maintenance
51 import plugin as lib_plugin
52 import path as lib_path
53 import common as lib_common
54 import language as lib_language
55
56
57
58
59
60 MAINTENANCE_MODE = False
61
62
63
64
65
66 CACHE_PERMANENT = 0
67
68
69
70
71 CACHE_TEMPORARY = -1
72
73
74
75
76 CACHE_DISABLED = 0
77
78
79
80
81 CACHE_NORMAL = 1
82
83
84
85
86
87
88 CACHE_AGGRESSIVE = 2
89
90
91
92
93
94
95
96
97 WATCHDOG_ALERT = 1
98
99
100
101
102
103
104
105 WATCHDOG_CRITICAL = 2
106
107
108
109
110
111
112
113
114 WATCHDOG_ERROR = 3
115
116
117
118
119
120
121
122
123 WATCHDOG_WARNING = 4
124
125
126
127
128
129
130
131 WATCHDOG_NOTICE = 5
132
133
134
135
136
137
138
139
140 WATCHDOG_INFO = 6
141
142
143
144
145
146
147
148
149 WATCHDOG_DEBUG = 7
150
151
152
153
154 DRUPAL_BOOTSTRAP_CONFIGURATION = 0
155
156
157
158
159
160 DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE = 1
161
162
163
164
165 DRUPAL_BOOTSTRAP_DATABASE = 2
166
167
168
169
170 DRUPAL_BOOTSTRAP_ACCESS = 3
171
172
173
174
175 DRUPAL_BOOTSTRAP_SESSION = 4
176
177
178
179
180
181 DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE = 5
182
183
184
185
186 DRUPAL_BOOTSTRAP_LANGUAGE = 6
187
188
189
190
191 DRUPAL_BOOTSTRAP_PATH = 7
192
193
194
195
196
197 DRUPAL_BOOTSTRAP_FULL = 8
198
199
200
201
202 DRUPAL_ANONYMOUS_RID = 9
203
204
205
206
207 DRUPAL_AUTHENTICATED_RID = 10
208
209
210
211
212 LANGUAGE_NEGOTIATION_NONE = 0
213
214
215
216
217
218 LANGUAGE_NEGOTIATION_PATH_DEFAULT = 1
219
220
221
222
223
224
225 LANGUAGE_NEGOTIATION_PATH = 2
226
227
228
229
230
231 LANGUAGE_NEGOTIATION_DOMAIN = 3
232
233
235 """
236 Start the timer with the specified name. If you start and stop
237 the same timer multiple times, the measured intervals will be
238 accumulated.
239
240 @param name
241 The name of the timer.
242 """
243 if lib_appglobals.timers == None:
244 lib_appglobals.timers = {};
245 if not php.isset(lib_appglobals.timers, name):
246 lib_appglobals.timers[name] = {}
247 (usec, sec) = php.explode(' ', php.microtime());
248 lib_appglobals.timers[name]['start'] = float(usec) + float(sec);
249 lib_appglobals.timers[name]['count'] = \
250 ((lib_appglobals.timers[name]['count'] + 1) if \
251 php.isset(lib_appglobals.timers[name],'count') else 1);
252
253
255 """
256 Read the current timer value without stopping the timer.
257
258 @param name
259 The name of the timer.
260 @return
261 The current timer value in ms.
262 """
263 if (php.isset(lib_appglobals.timers[name], 'start')):
264 (usec, sec) = php.explode(' ', php.microtime());
265 stop = float(usec) + float(sec);
266 diff = round((stop - lib_appglobals.timers[name]['start']) * 1000, 2);
267 if (php.isset(lib_appglobals.timers[name], 'time')):
268 diff += lib_appglobals.timers[name]['time'];
269 return diff;
270
271
273 """
274 Stop the timer with the specified name.
275
276 @param name
277 The name of the timer.
278 @return
279 A timer array. The array contains the number of times the
280 timer has been started and stopped (count) and the accumulated
281 timer value in ms (time).
282 """
283 lib_appglobals.timers[name]['time'] = lib_appglobals.timer_read(name);
284 del(lib_appglobals.timers[name]['start']);
285 return lib_appglobals.timers[name];
286
287
288 -def conf_path(require_settings = True, reset = False):
289 """
290 Find the appropriate configuration directory.
291
292 Try finding a matching configuration directory by stripping the website's
293 hostname from left to right and pathname from right to left. The first
294 configuration file found will be used; the remaining will ignored. If no
295 configuration file is found, return a default value 'confdir/default'.
296
297 Example for a fictitious site installed at
298 http://www.drupal.org:8080/mysite/test/ the 'settings.php' is searched in
299 the following directories:
300
301 1. confdir/8080.www.drupal.org.mysite.test
302 2. confdir/www.drupal.org.mysite.test
303 3. confdir/drupal.org.mysite.test
304 4. confdir/org.mysite.test
305
306 5. confdir/8080.www.drupal.org.mysite
307 6. confdir/www.drupal.org.mysite
308 7. confdir/drupal.org.mysite
309 8. confdir/org.mysite
310
311 9. confdir/8080.www.drupal.org
312 10. confdir/www.drupal.org
313 11. confdir/drupal.org
314 12. confdir/org
315
316 13. confdir/default
317
318 @param require_settings
319 Only configuration directories with an existing settings.php file
320 will be recognized. Defaults to TRUE. During initial installation,
321 this is set to FALSE so that Drupal can detect a matching directory,
322 then create a new settings.php file in it.
323 @param reset
324 Force a full search for matching directories even if one had been
325 found previously.
326 @return
327 The path of the matching directory.
328 """
329 return 'sites/default'
330
331
333 """
334 Unsets all disallowed global variables. See allowed for what's allowed.
335 """
336
337 pass;
338
339
341 """
342 Loads the configuration and sets the base URL, cookie domain, and
343 session name correctly.
344 """
345
346
347 if (lib_appglobals.base_url != None):
348
349 parts = php.parse_url(lib_appglobals.base_url);
350 if (not php.isset(parts, 'path')):
351 parts['path'] = '';
352 lib_appglobals.base_path = parts['path'] + '/';
353
354 lib_appglobals.base_root = \
355 php.substr(lib_appglobals.base_url, 0, \
356 php.strlen(lib_appglobals.base_url) - \
357 php.strlen(parts['path']));
358 else:
359
360 lib_appglobals.base_root = \
361 ('https' if (php.isset(php.SERVER, 'HTTPS') and \
362 php.SERVER['HTTPS'] == 'on') else 'http');
363
364
365 lib_appglobals.base_root += '://' + \
366 php.preg_replace('/[^a-z0-9-:._]/i', '', \
367 php.SERVER['HTTP_HOST']);
368 lib_appglobals.base_url = lib_appglobals.base_root;
369
370
371 dir = php.trim(php.dirname(php.SERVER['SCRIPT_NAME']), '\,/');
372 if (len(dir) > 0):
373 lib_appglobals.base_path = "/dir";
374 lib_appglobals.base_url += lib_appglobals.base_path
375 lib_appglobals.base_path += '/';
376 else:
377 lib_appglobals.base_path = '/';
378 if (settings.cookie_domain != None):
379
380 session_name_ = settings.cookie_domain;
381 else:
382
383
384 session_name_ = php.explode('://', lib_appglobals.base_url, 2)[1]
385
386 if (not php.empty(php.SERVER['HTTP_HOST'])):
387 settings.cookie_domain = check_plain(php.SERVER['HTTP_HOST']);
388
389 settings.cookie_domain = php.ltrim(settings.cookie_domain, '.');
390 if (php.strpos(settings.cookie_domain, 'www.') == 0):
391 settings.cookie_domain = php.substr(settings.cookie_domain, 4);
392 settings.cookie_domain = php.explode(':', settings.cookie_domain);
393 settings.cookie_domain = '.' + settings.cookie_domain[0];
394
395
396
397 if (php.count(php.explode('.', settings.cookie_domain)) > 2 and not \
398 php.is_numeric(php.str_replace('.', '', settings.cookie_domain))):
399 php.ini_set('session.cookie_domain', settings.cookie_domain);
400
401 lib_session.name('SESS' + php.md5(session_name_));
402
403
404
406 """
407 Returns and optionally sets the filename for a system item (plugin,
408 theme, etc.). The filename, whether provided, cached, or retrieved
409 from the database, is only returned if the file exists.
410
411 This def plays a key role in allowing Drupal's resources (plugins
412 and themes) to be located in different places depending on a site's
413 configuration. For example, a plugin 'foo' may legally be be located
414 in any of these three places:
415
416 plugins/foo/__init__.py
417 sites/all/plugins/foo/__init__.py
418 sites/example.com/plugins/foo/__init__.py
419
420 Calling drupal_get_filename('plugin', 'foo') will give you one of
421 the above, depending on where the plugin is located.
422
423 @param type
424 The type of the item (i.e. theme, theme_engine, plugin).
425 @param name
426 The name of the item for which the filename is requested.
427 @param filename
428 The filename of the item if it is to be set explicitly rather
429 than by consulting the database.
430
431 @return
432 The filename of the requested item.
433 """
434 php.static(drupal_get_filename, 'files', {})
435 file = lib_database.result(lib_database.query(\
436 "SELECT filename FROM {system} WHERE name = '%s' AND type = '%s'", \
437 name, type_))
438 if (not php.isset(drupal_get_filename.files, type_)):
439 drupal_get_filename.files[type_] = {}
440 if (filename is not None and php.file_exists(filename)):
441 drupal_get_filename.files[type_][name] = filename;
442 elif (php.isset(drupal_get_filename.files[type_], name)):
443
444 pass;
445
446
447
448
449 elif (lib_database.is_active() and (file and php.file_exists(file))):
450 drupal_get_filename.files[type_][name] = file;
451 else:
452
453
454 config = conf_path();
455 if type_ == 'theme_engine':
456 dir_ = 'themes/engines'
457 file = "%s.engine" % name
458 else:
459 dir_ = '%ss' % type_
460 file = "__init__.py"
461 fileVals = {'name':name, 'file':file, 'dir':dir_, 'config':config};
462 fileChecker = (
463
464
465 "%(config)s/%(dir)s/%(name)s/%(file)s" % fileVals,
466
467
468 "%(dir)s/%(name)s/%(file)s" % fileVals
469 )
470 for file_ in fileChecker:
471 if (php.file_exists(file_)):
472 drupal_get_filename.files[type_][name] = file_;
473 break;
474 if (php.isset(drupal_get_filename.files[type_], name)):
475 return drupal_get_filename.files[type_][name];
476
477
478
480 """
481 Load the persistent variable table.
482
483 The variable table is composed of values that have been saved in the table
484 with variable_set() as well as those explicitly specified
485 in the configuration file.
486 """
487
488
489 cached = lib_cache.get('variables', 'cache');
490 if (cached):
491 variables = cached.data;
492 else:
493 variables = {}
494 result = lib_database.query('SELECT * FROM {variable}');
495 while True:
496 variable = lib_database.fetch_object(result);
497 if (not variable):
498 break;
499 variables[variable.name] = php.unserialize(variable.value);
500 lib_cache.set('variables', variables);
501 for name,value in conf_.items():
502 variables[name] = value;
503 return variables;
504
505
506
508 """
509 Return a persistent variable.
510
511 @param name
512 The name of the variable to return.
513 @param default
514 The default value to use if this variable has never been set.
515 @return
516 The value of the variable.
517 """
518 return (settings.conf[name] if php.isset(settings.conf, name) else default_);
519
520
522 """
523 Set a persistent variable.
524
525 @param name
526 The name of the variable to set.
527 @param value
528 The value to set. This can be any PHP data type; these functions take care
529 of serialization as necessary.
530 """
531 serialized_value = php.serialize(value);
532 db_query("UPDATE {variable} SET value = '%s' WHERE name = '%s'", \
533 serialized_value, name);
534 if (db_affected_rows() == 0):
535 db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", \
536 name, serialized_value);
537 cache_clear_all('variables', 'cache');
538 settings.conf[name] = value;
539
540
542 """
543 Unset a persistent variable.
544
545 @param name
546 The name of the variable to undefine.
547 """
548 db_query("DELETE FROM {variable} WHERE name = '%s'", name);
549 cache_clear_all('variables', 'cache');
550 del(settings.conf[name]);
551
552
553
555 """
556 Retrieve the current page from the cache.
557
558 Note: we do not serve cached pages when status messages are waiting (from
559 a redirected form submission which was completed).
560
561 @param status_only
562 When set to TRUE, retrieve the status of the page cache only
563 (whether it was started in this request or not).
564 """
565 cache = None;
566 if (not lib_appglobals.user.uid and \
567 (php.SERVER['REQUEST_METHOD'] == 'GET' or \
568 php.SERVER['REQUEST_METHOD'] == 'HEAD') and \
569 php.count(drupal_set_message()) == 0):
570 cache = lib_cache.get(lib_appglobals.base_root + request_uri(), \
571 'cache_page');
572 if (php.empty(cache)):
573 ob_start()
574 return cache;
575
576
577
579 """
580 Call all init or exit hooks without including all plugins.
581
582 @param hook
583 The name of the bootstrap hook we wish to invoke.
584 """
585 for plugin_ in lib_plugin.list_(True, True):
586 lib_plugin.invoke(plugin_, hook);
587
588
590 """
591 Includes a file with the provided type and name. This prevents
592 including a theme, engine, plugin, etc., more than once.
593
594 @param type
595 The type of item to load (i.e. theme, theme_engine, plugin).
596 @param name
597 The name of the item to load.
598
599 @return
600 TRUE if the item is loaded or has already been loaded.
601 """
602 php.static(drupal_load, 'files', {})
603 if (not php.isset(drupal_load.files, type)):
604 drupal_load.files[type_] = {}
605 if (php.isset(drupal_load.files[type_], name)):
606 return True
607 else:
608 filename = drupal_get_filename(type_, name);
609 if (filename != False):
610 lib_plugin.plugins[name] = DrupyImport.import_file(filename)
611 drupal_load.files[type_][name] = True;
612 return True;
613 else:
614 return False;
615
616
618 """
619 Set HTTP headers in preparation for a page response.
620
621 Authenticated users are always given a 'no-cache' php.header, and will
622 fetch a fresh page on every request. This prevents authenticated
623 users seeing locally cached pages that show them as logged out.
624
625 @see page_set_cache()
626 """
627 php.header("Expires: Sun, 19 Nov 1978 05:00:00 GMT");
628 php.header("Last-Modified: " + php.gmdate("%D, %d %M %Y %H:%i:%s") + " GMT");
629 php.header("Cache-Control: store, no-cache, must-revalidate");
630 php.header("Cache-Control: post-check=0, pre-check=0", False);
631
632
633
635 """
636 Set HTTP headers in preparation for a cached page response.
637
638 The general approach here is that anonymous users can keep a local
639 cache of the page, but must revalidate it on every request. Then,
640 they are given a '304 Not Modified' response as long as they stay
641 logged out and the page has not been modified.
642 """
643
644 last_modified = php.gmdate('D, d M Y H:i:s', cache.created) + ' GMT';
645 etag = '"' + drupy_md5(last_modified) + '"';
646
647 if_modified_since = (php.stripslashes(php.SERVER['HTTP_IF_MODIFIED_SINCE']) \
648 if php.isset(php.SERVER, 'HTTP_IF_MODIFIED_SINCE') else False);
649 if_none_match = (php.stripslashes(php.SERVER['HTTP_IF_NONE_MATCH']) \
650 if php.isset(php.SERVER, 'HTTP_IF_NONE_MATCH') else False);
651 if (if_modified_since and if_none_match
652 and if_none_match == etag
653 and if_modified_since == last_modified):
654 php.header('HTTP/1.1 304 Not Modified');
655
656
657 php.header("Etag: %(etag)s" % {'etag':etag});
658 exit();
659
660 php.header("Last-Modified: %(last_modified)s" % \
661 {'last_modified':last_modified});
662 php.header("Etag: %(etag)s" % {'etag':etag});
663
664 php.header("Expires: Sun, 19 Nov 1978 05:00:00 GMT");
665 php.header("Cache-Control: must-revalidate");
666 if (variable_get('page_compression', True)):
667
668 if (php.strpos(php.SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') == False and \
669 php.function_exists('gzencode')):
670
671 cache.data = php.gzinflate(php.substr(php.substr(cache.data, 10), 0, -8));
672 elif (php.function_exists('gzencode')):
673 php.header('Content-Encoding: gzip');
674
675
676
677 headers = php.explode("\n", cache.headers);
678 for php.header_ in headers:
679 php.header(php.header_);
680 print cache.data;
681
682
684 """
685 Define the critical hooks that force plugins to always be loaded.
686 """
687 return ['boot', 'exit'];
688
689
691 """
692 Unserializes and appends elements from a serialized string.
693
694 @param obj
695 The object to which the elements are appended.
696 @param field
697 The attribute of obj whose value should be unserialized.
698 """
699 if hasattr(obj, field) and not php.empty(getattr(obj, field)):
700 data = php.unserialize(getattr(obj, field))
701 else:
702 data = None
703 if (hasattr(obj, field) and not php.empty(data)):
704 for key,value in data.items():
705 if (not php.isset(obj, key)):
706 setattr(obj, key, value)
707 return obj;
708
709
711 """
712 Return the URI of the referring page.
713 """
714 if (php.isset(php.SERVER, 'HTTP_REFERER')):
715 return php.SERVER['HTTP_REFERER'];
716
717
719 """
720 Encode special characters in a plain-text string for display as HTML.
721
722 Uses drupal_validate_utf8 to prevent cross site scripting attacks on
723 Internet Explorer 6.
724 """
725 return (php.htmlspecialchars(text, php.ENT_QUOTES) if \
726 drupal_validate_utf8(text) else '');
727
728
730 """
731 Checks whether a string is valid UTF-8.
732
733 All functions designed to filter input should use drupal_validate_utf8
734 to ensure they operate on valid UTF-8 strings to prevent bypass of the
735 filter.
736
737 When text containing an invalid UTF-8 lead byte (0xC0 - 0xFF) is presented
738 as UTF-8 to Internet Explorer 6, the program may misinterpret subsequent
739 bytes. When these subsequent bytes are HTML control characters such as
740 quotes or angle brackets, parts of the text that were deemed safe by filters
741 end up in locations that are potentially unsafe; An onerror attribute that
742 is outside of a tag, and thus deemed safe by a filter, can be interpreted
743 by the browser as if it were inside the tag.
744
745 This def exploits preg_match behaviour (since PHP 4.3.5) when used
746 with the u modifier, as a fast way to find invalid UTF-8. When the matched
747 string contains an invalid byte sequence, it will fail silently.
748
749 preg_match may not fail on 4 and 5 octet sequences, even though they
750 are not supported by the specification.
751
752 The specific preg_match behaviour is present since PHP 4.3.5.
753
754 @param text
755 The text to check.
756 @return
757 TRUE if the text is valid UTF-8, FALSE if not.
758 """
759 if (php.strlen(text) == 0):
760 return True;
761 return (php.preg_match('/^./us', text) == 1);
762
763
765 """
766 Since php.SERVER['php.REQUEST_URI'] is only available on Apache, we
767 generate an equivalent using other environment variables.
768 """
769 if (php.isset(php.SERVER, 'REQUEST_URI')):
770 uri = php.SERVER['REQUEST_URI'];
771 else:
772 if (php.isset(php.SERVER, 'argv')):
773 uri = php.SERVER['SCRIPT_NAME'] + '?' + php.SERVER['argv'][0];
774 elif (php.isset(php.SERVER, 'QUERY_STRING')):
775 uri = php.SERVER['SCRIPT_NAME'] + '?' + php.SERVER['QUERY_STRING'];
776 else:
777 uri = php.SERVER['SCRIPT_NAME'];
778 return uri;
779
780
781
784 """
785 Log a system message.
786
787 @param type
788 The category to which this message belongs.
789 @param message
790 The message to store in the log. See t() for documentation
791 on how message and variables interact. Keep message
792 translatable by not concatenating dynamic values into it!
793 @param variables
794 Array of variables to replace in the message on display or
795 NULL if message is already translated or not possible to
796 translate.
797 @param severity
798 The severity of the message, as per RFC 3164
799 @param link
800 A link to associate with the message.
801
802 @see watchdog_severity_levels()
803 """
804
805 log_message = {
806 'type' : type,
807 'message' : message,
808 'variables' : variables,
809 'severity' : severity,
810 'link' : link,
811 'user' : lib_appglobals.user,
812 'request_uri' : lib_appglobals.base_root + request_uri(),
813 'referer' : referer_uri(),
814 'ip' : ip_address(),
815 'timestamp' : php.time_(),
816 }
817
818 for plugin_ in lib_plugin.implements('watchdog', True):
819 lib_plugin.invoke(plugin_, 'watchdog', log_message);
820
821
823 """
824 Set a message which reflects the status of the performed operation.
825
826 If the def is called with no arguments, this def returns all set
827 messages without clearing them.
828
829 @param message
830 The message should begin with a capital letter and always ends with a
831 period '.'.
832 @param type
833 The type of the message. One of the following values are possible:
834 - 'status'
835 - 'warning'
836 - 'error'
837 @param repeat
838 If this is FALSE and the message is already set, then the message won't
839 be repeated.
840 """
841 if (message):
842 if (not php.isset(php.SESSION, 'messages')):
843 php.SESSION['messages'] = {};
844 if (not php.isset(php.SESSION['messages'], type)):
845 php.SESSION['messages'][type] = [];
846 if (repeat or not php.in_array(message, php.SESSION['messages'][type])):
847 php.SESSION['messages'][type].append( message );
848
849 return (php.SESSION['messages'] if php.isset(php.SESSION, 'messages') else \
850 None);
851
852
854 """
855 Return all messages that have been set.
856
857 @param type
858 (optional) Only return messages of this type.
859 @param clear_queue
860 (optional) Set to FALSE if you do not want to clear the messages queue
861 @return
862 An associative array, the key is the message type, the value an array
863 of messages. If the type parameter is passed, you get only that type,
864 or an empty array if there are no such messages. If type is not passed,
865 all message types are returned, or an empty array if none exist.
866 """
867 messages = drupal_set_message();
868 if (not php.empty('messages')):
869 if (type != None and type != False):
870 if (clear_queue):
871 del(php.SESSION['messages'][type]);
872 if (php.isset(messages, type)):
873 return {type : messages[type]};
874 else:
875 if (clear_queue):
876 del(php.SESSION['messages']);
877 return messages;
878 return {};
879
880
882 """
883 Check to see if an IP address has been blocked.
884
885 Blocked IP addresses are stored in the database by default. However for
886 performance reasons we allow an override in settings.php. This allows us
887 to avoid querying the database at this critical stage of the bootstrap if
888 an administrative interface for IP address blocking is not required.
889
890 @param $ip string
891 IP address to check.
892 @return bool
893 TRUE if access is denied, FALSE if access is allowed.
894 """
895
896
897
898 blocked_ips = variable_get('blocked_ips', None);
899 if (blocked_ips != None and php.is_array(blocked_ips)):
900 return php.in_array(ip, blocked_ips)
901 else:
902 sql = "SELECT 1 FROM {blocked_ips} WHERE ip = '%s'";
903 return (lib_database.result(lib_database.query(sql, ip)) != False)
904
905
920
921
922
924 """
925 A string describing a phase of Drupal to load. Each phase adds to the
926 previous one, so invoking a later phase automatically runs the earlier
927 phases too. The most important usage is that if you want to access the
928 Drupal database from a script without loading anything else, you can
929 include bootstrap.inc, and call drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE).
930
931 @param phase
932 A constant. Allowed values are:
933 DRUPAL_BOOTSTRAP_CONFIGURATION: initialize configuration.
934 DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE: try to call a non-database cache
935 fetch routine.
936 DRUPAL_BOOTSTRAP_DATABASE: initialize database layer.
937 DRUPAL_BOOTSTRAP_ACCESS: identify and reject banned hosts.
938 DRUPAL_BOOTSTRAP_SESSION: initialize session handling.
939 DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE: load bootstrap.inc and plugin.inc,
940 start the variable system and try to serve a page from the cache.
941 DRUPAL_BOOTSTRAP_LANGUAGE: identify the language used on the page.
942 DRUPAL_BOOTSTRAP_PATH: set php.GET['q'] to Drupal path of request.
943 DRUPAL_BOOTSTRAP_FULL: Drupal is fully loaded, validate and fix
944 input data.
945 """
946
947
948 if 'q' not in php.GET:
949 php.GET['q'] = 'node'
950
951
952 phase_index = 0;
953 phases = range(DRUPAL_BOOTSTRAP_CONFIGURATION, DRUPAL_BOOTSTRAP_FULL+1);
954 while (phase >= phase_index and php.isset(phases, phase_index)):
955 current_phase = phases[phase_index];
956
957
958 phase_index += 1;
959 _drupal_bootstrap(current_phase);
960
961
962
1024
1025
1027 """
1028 Enables use of the theme system without requiring database access.
1029
1030 Loads and initializes the theme system for site installs, updates and when
1031 the site is in offline mode. This also applies when the database fails.
1032
1033 @see _drupal_maintenance_theme()
1034 """
1035 lib_theme_maintenance._drupal_maintenance_theme();
1036
1037
1039 """
1040 Return the name of the localisation function. Use in code that needs to
1041 run both during installation and normal operation.
1042 """
1043 php.static(get_t, 't')
1044 if (get_t.t == None):
1045 get_t.t = ('st' if php.function_exists('install_main') else 't');
1046 return get_t.t;
1047
1048
1049
1051 """
1052 Choose a language for the current page, based on site and user preferences.
1053 """
1054
1055
1056
1057 if (variable_get('language_count', 1) == 1):
1058 lib_appglobals.language = language_default();
1059 else:
1060 lib_appglobals.language = lib_language.initialize();
1061
1062
1064 """
1065 Get a list of languages set up indexed by the specified key
1066
1067 @param field The field to index the list with.
1068 @param reset Boolean to request a reset of the list.
1069 """
1070 php.static(language_list, 'languages')
1071
1072 if (reset):
1073 languages_list.languages = {};
1074
1075 if (languages_list.languages == None):
1076 if (variable_get('language_count', 1) > 1 or plugin_exists('locale')):
1077 result = db_query(\
1078 'SELECT# FROM {languages} ORDER BY weight ASC, name ASC');
1079 while True:
1080 row = db_fetch_object(result);
1081 if row == None:
1082 break;
1083 languages_list.languages['language'][row.language] = row;
1084 else:
1085
1086 default_ = language_default();
1087 languages_list.languages['language'][default_.language] = default_;
1088
1089 if (not php.isset(languages_list.languages, field)):
1090 languages_list.languages[field] = {};
1091 for lang in languages_list.languages['language']:
1092
1093 if (php.in_array(field, ['enabled', 'weight'])):
1094 languages_list.languages[field][lang.field][lang.language] = lang;
1095 else:
1096 languages_list.languages[field][lang.field] = lang;
1097 return languages_list.languages[field];
1098
1099
1100
1102 """
1103 Default language used on the site
1104
1105 @param property
1106 Optional property of the language object to return
1107 """
1108 language_local = variable_get('language_default', php.object_({
1109 'language' : 'en',
1110 'name' : 'English',
1111 'native' : 'English',
1112 'direction' : 0,
1113 'enabled' : 1,
1114 'plurals' : 0,
1115 'formula' : '',
1116 'domain' : '',
1117 'prefix' : '',
1118 'weight' : 0,
1119 'javascript' : ''
1120 }));
1121 return (getattr(language_local, property) if (property != None) else \
1122 language_local);
1123
1124
1126 """
1127 If Drupal is behind a reverse proxy, we use the X-Forwarded-For header
1128 instead of $_SERVER['REMOTE_ADDR'], which would be the IP address of
1129 the proxy server, and not the client's. If Drupal is run in a cluster
1130 we use the X-Cluster-Client-Ip header instead.
1131
1132 @param $reset
1133 Reset the current IP address saved in static.
1134 @return
1135 IP address of client machine, adjusted for reverse proxy and/or cluster
1136 environments.
1137 """
1138 php.static(ip_address, 'ip_address')
1139 if (ip_address.ip_address is None or reset):
1140 ip_address.ip_address = php.SERVER['REMOTE_ADDR'];
1141 if (variable_get('reverse_proxy', 0)):
1142 if (php.array_key_exists('HTTP_X_FORWARDED_FOR', php.SERVER)):
1143
1144
1145 reverse_proxy_addresses = variable_get('reverse_proxy_addresses', \
1146 tuple());
1147 if (not php.empty(reverse_proxy_addresses) and \
1148 php.in_array(ip_address.ip_address, reverse_proxy_addresses, \
1149 True)):
1150
1151
1152 ip_address.ip_address = php.array_pop(\
1153 php.explode(',', php.SERVER['HTTP_X_FORWARDED_FOR']));
1154
1155
1156
1157
1158
1159 if (php.array_key_exists('HTTP_X_CLUSTER_CLIENT_IP', php.SERVER)):
1160 ip_address.ip_address = php.SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
1161 return ip_address.ip_address;
1162
1163
1164
1166 """
1167 Confirm that a function is available.
1168
1169 If the function is already available, this function does nothing.
1170 If the function is not available, it tries to load the file where the
1171 function lives. If the file is not available, it returns False, so that it
1172 can be used as a drop-in replacement for php.function_exists().
1173
1174 DRUPY(BC): This function needs to be heavily modified
1175
1176 @param function
1177 The name of the function to check or load.
1178 @param scope
1179 Scope to check
1180 @return
1181 True if the function is now available, False otherwise.
1182 """
1183
1184 return php.function_exists(function, scope)
1185
1186
1187
1189 """
1190 Confirm that an interface is available.
1191
1192 This function parallels drupal_function_exists(), but is rarely
1193 called directly. Instead, it is registered as an spl_autoload()
1194 handler, and PHP calls it for us when necessary.
1195
1196 @param interface
1197 The name of the interface to check or load.
1198 @return
1199 True if the interface is currently available, False otherwise.
1200 """
1201 return _registry_check_code('interface', interface)
1202
1203
1205 """
1206 Confirm that a class is available.
1207
1208 This function parallels drupal_function_exists(), but is rarely
1209 called directly. Instead, it is registered as an spl_autoload()
1210 handler, and PHP calls it for us when necessary.
1211
1212 @param class
1213 The name of the class to check or load.
1214 @return
1215 True if the class is currently available, False otherwise.
1216 """
1217 return _registry_check_code('class', class_)
1218
1219
1221 """
1222 Helper for registry_check_{interface, class}.
1223 """
1224 file = db_result(db_query(\
1225 "SELECT filename FROM {registry} WHERE name = '%s' AND type = '%s'", \
1226 name, type_))
1227 if (file):
1228 php.require_once(file)
1229 registry_mark_code(type_, name)
1230 return True
1231
1232
1252
1253
1254
1256 """
1257 Rescan all enabled plugins and rebuild the registry.
1258
1259 Rescans all code in plugins or includes directory, storing a mapping of
1260 each function, file, and hook implementation in the database.
1261 """
1262 _registry_rebuild()
1263
1264
1265
1287
1288
1290 """
1291 Save the files required by the registry for this path.
1292 """
1293 used_code = registry_mark_code(None, None, True)
1294 if (used_code):
1295 files = []
1296 type_sql = []
1297 params = []
1298 for type,names in used_code.items():
1299 type_sql.append( "(name IN (" + db_placeholders(names, 'varchar') + \
1300 ") AND type = '%s')" )
1301 params = php.array_merge(params, names)
1302 params.append( type )
1303 res = db_query("SELECT DISTINCT filename FROM {registry} WHERE " + \
1304 php.implode(' OR ', type_sql), params)
1305 while True:
1306 row = db_fetch_object(res)
1307 if (row == None):
1308 break
1309 files.append( row.filename )
1310 if (files):
1311 sort(files);
1312
1313
1314 if (files != registry_load_path_files(True)):
1315 menu = menu_get_item();
1316 cache_set('registry:' + menu['path'], php.implode(';', files), \
1317 'cache_registry');
1318
1319
1334
1335
1348