├── AUTHORS ├── README.markdown ├── app ├── config │ └── config.inc.php ├── controllers │ └── api-m_oauth_controller.php └── lib │ ├── bootstrap.inc.php │ ├── class.api-m_oauth_helper.inc.php │ └── class.oauth.inc.php └── lib ├── class.generic_utils.inc.php ├── class.route.inc.php ├── class.scribe.inc.php ├── class.sky_smarty.inc.php └── errors.inc.php /AUTHORS: -------------------------------------------------------------------------------- 1 | Frank Denis 2 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | PHP OAuth2 provider 2 | =================== 3 | 4 | An OAuth2 provider for PHP. 5 | -------------------------------------------------------------------------------- /app/config/config.inc.php: -------------------------------------------------------------------------------- 1 | assign('form_check', $wanted_form_check); 14 | $obj_smarty->assign('user_name', $user_name); 15 | $obj_smarty->assign('user_password', $user_password); 16 | $obj_smarty->assign('oauth_redirect_uri', $redirect_uri); 17 | $obj_smarty->assign('oauth_client_id', $client_id); 18 | $obj_smarty->assign('facebook_login_uri', $facebook_login_uri); 19 | $obj_smarty->assign('signon_sky_uri', $signon_sky_uri); 20 | $obj_smarty->assign('flash', $flash); 21 | 22 | return $obj_smarty->fetch('api-m/authorize.tpl'); 23 | } 24 | 25 | static function _view_form($obj_smarty, &$user_id, &$user_name, $facebook_login_uri, $signon_sky_uri, 26 | $client_id, $redirect_uri) { 27 | $user_id = NULL; 28 | $user_name = NULL; 29 | 30 | header('Content-Type: text/html; charset=UTF-8'); 31 | $user_name = trim((string) params('user_name')); 32 | $user_password = trim((string) params('user_password')); 33 | $form_check = (string) params('form_check'); 34 | assert(!empty($facebook_login_uri)); 35 | $flash = array(); 36 | if (empty($redirect_uri)) { 37 | return array('return_code' => -1, 38 | 'error_message' => 'Missing redirect URI'); 39 | } 40 | if (empty($client_id)) { 41 | return array('return_code' => -1, 42 | 'error_message' => 'Missing client ID'); 43 | } 44 | if (empty($form_check)) { 45 | return self::_get_form($obj_smarty, $user_name, $user_password, $flash, 46 | $redirect_uri, $client_id, $facebook_login_uri, 47 | $signon_sky_uri); 48 | } 49 | if (strcasecmp($_SERVER['REQUEST_METHOD'], 'POST') !== 0) { 50 | return array('return_code' => -1, 51 | 'error_message' => 'Unsupported method'); 52 | } 53 | if (Utils::check_csrf_token((string) $form_check, 'oauth_login_form', FALSE) !== TRUE) { 54 | return array('return_code' => -1, 55 | 'error_message' => 'Form check mismatch'); 56 | } 57 | if (empty($user_name)) { 58 | $flash['user_name'] = 'Missing username'; 59 | } 60 | if (empty($user_password)) { 61 | $flash['user_password'] = 'Missing password'; 62 | } 63 | if (!empty($flash)) { 64 | return self::_get_form($obj_smarty, $user_name, $user_password, $flash, 65 | $redirect_uri, $client_id, $facebook_login_uri, 66 | $signon_sky_uri); 67 | } 68 | $user_id = NULL; 69 | try { 70 | if (Auth::connect_with_local_account($user_name, $user_password) === TRUE) { 71 | $user_id = Auth::get_user_id(); 72 | $user_name_ = Auth::get_user_name(); 73 | assert(strcasecmp($user_name_, $user_name) === 0); 74 | $user_name = $user_name_; 75 | } 76 | } catch (\Exception $e) { } 77 | if (empty($user_id) || empty($user_name)) { 78 | $flash['form'] = 'The username or password is incorrect'; 79 | 80 | return self::_get_form($obj_smarty, $user_name, $user_password, $flash, 81 | $redirect_uri, $client_id, $facebook_login_uri, 82 | $signon_sky_uri); 83 | } 84 | return NULL; 85 | } 86 | 87 | static function authorize() { 88 | Utils::http_nocache(); 89 | $type = (string) params('type'); 90 | $redirect_uri = (string) params('redirect_uri'); 91 | $client_id = (string) params('client_id'); 92 | $state = (string) params('state'); 93 | if (empty($type)) { 94 | $type = 'user_agent'; 95 | } 96 | $display = NULL; 97 | if (!empty($_SERVER['HTTP_USER_AGENT']) && 98 | preg_match('/Apple.+Mobile/', $_SERVER['HTTP_USER_AGENT']) > 0) { 99 | $display = 'touch'; 100 | } 101 | if (empty($redirect_uri)) { 102 | return array('return_code' => -1, 103 | 'error_message' => 'Missing redirect URI'); 104 | } 105 | if (empty($client_id)) { 106 | return array('return_code' => -1, 107 | 'error_message' => 'Missing client ID'); 108 | } 109 | try { 110 | OAuth::get_client_secret($client_id); 111 | } catch (\Exception $e) { 112 | return array('return_code' => -1, 113 | 'error_message' => 'Unregistered application'); 114 | } 115 | $oauth_redirect_uri = $redirect_uri; 116 | OAuth::check_redirect_uri($client_id, $oauth_redirect_uri); 117 | if (!empty($state)) { 118 | $oauth_redirect_uri = Utils::construct_uri_from_base_uri_and_args 119 | (array('uri' => $oauth_redirect_uri, 120 | 'state' => $state)); 121 | } 122 | $facebook_redirect_uri = Utils::construct_uri_from_base_uri_and_args 123 | (array('uri' => FBLINK_VERIFY_URL, 124 | 'oauth_client_id' => $client_id, 125 | 'oauth_redirect_uri' => $oauth_redirect_uri)); 126 | $args = array('uri' => FACEBOOK_AUTHORIZE_URI_BASE, 127 | 'redirect_uri' => $facebook_redirect_uri); 128 | if (!empty($display)) { 129 | $args['display'] = $display; 130 | } 131 | $facebook_login_uri = Utils::construct_uri_from_base_uri_and_args($args); 132 | $args = array('uri' => '/auth.php/signon-sky.html', 133 | 'oauth_client_id' => $client_id, 134 | 'oauth_redirect_uri' => $oauth_redirect_uri); 135 | if (!empty($display)) { 136 | $args['display'] = $display; 137 | } 138 | $signon_sky_uri = Utils::construct_uri_from_base_uri_and_args($args); 139 | $user_id = NULL; 140 | $user_name = NULL; 141 | if (!Auth::is_logged()) { 142 | $obj_smarty = new SkySmarty(); 143 | $res = self::_view_form($obj_smarty, $user_id, $user_name, $facebook_login_uri, $signon_sky_uri, 144 | $client_id, $oauth_redirect_uri); 145 | if (!empty($res)) { 146 | return $res; 147 | } 148 | } else { 149 | $user_id = Auth::get_user_id(); 150 | $user_name = Auth::get_user_name(); 151 | } 152 | assert($user_id !== NULL); 153 | assert(!empty($user_name)); 154 | $expires_at = time() + OAUTH_CODE_EXPIRATION; 155 | $validation_code = 156 | OAUTH_VALIDATION_SCOPE . OAUTH_GLUE . $user_id . OAUTH_GLUE . $user_name . OAUTH_GLUE . 157 | $expires_at . OAUTH_GLUE . 158 | OAuth::get_validation_code_digest($user_id, $user_name, $expires_at, $client_id, $redirect_uri); 159 | $args = array('uri' => $redirect_uri, 160 | 'code' => $validation_code, 161 | 'expires_in' => OAUTH_CODE_EXPIRATION); 162 | if (!empty($state)) { 163 | $args['state'] = $state; 164 | } 165 | Utils::redirect_to_with_args($args); 166 | } 167 | 168 | static function access_token() { 169 | Utils::http_nocache(); 170 | $now = time(); 171 | $type = (string) params('type'); 172 | $state = (string) params('state'); 173 | $client_id = (string) params('client_id'); 174 | $redirect_uri = (string) params('redirect_uri'); 175 | $code = (string) params('code'); 176 | $refresh_token = (string) params('refresh_token'); 177 | $client_secret = (string) params('client_secret'); 178 | 179 | if (empty($type)) { 180 | $type = 'web_server'; 181 | } 182 | if (strcasecmp($type, 'web_server') === 0) { 183 | if (empty($redirect_uri)) { 184 | return array('error' => 'redirect_uri_mismatch'); 185 | } 186 | if (empty($code)) { 187 | return array('error' => 'bad_verification_code'); 188 | } 189 | } else if (strcasecmp($type, 'refresh') === 0) { 190 | $code = ''; 191 | $redirect_uri = ''; 192 | } 193 | if (empty($client_id)) { 194 | return array('error' => 'incorrect_client_credentials'); 195 | } 196 | try { 197 | $wanted_client_secret = OAuth::get_client_secret($client_id); 198 | if (Utils::secure_strings_are_equal($wanted_client_secret, $client_secret) !== TRUE) { 199 | throw new \Exception('Invalid client secret'); 200 | } 201 | } catch (\Exception $e) { 202 | return array('error' => 'incorrect_client_credentials'); 203 | } 204 | if (strcasecmp($type, 'web_server') === 0) { 205 | @list($scope, $user_id, $user_name, $expires_at, $digest) = explode(OAUTH_GLUE, $code); 206 | if ($scope !== OAUTH_VALIDATION_SCOPE) { 207 | return array('error' => 'incorrect_client_credentials'); 208 | } 209 | } else if (strcasecmp($type, 'refresh') === 0) { 210 | @list($scope, $user_id, $user_name, $expires_at, $digest) = explode(OAUTH_GLUE, $refresh_token); 211 | if ($scope !== OAUTH_REFRESH_TOKEN_SCOPE) { 212 | return array('error' => 'incorrect_client_credentials'); 213 | } 214 | } else { 215 | return array('error' => 'incorrect_client_credentials'); 216 | } 217 | if (empty($user_id) || empty($user_name) || empty($expires_at) || empty($digest)) { 218 | return array('error' => 'incorrect_client_credentials'); 219 | } 220 | if ($now > $expires_at) { 221 | return array('error' => 'code_expired'); 222 | } 223 | try { 224 | if (strcasecmp($type, 'web_server') === 0) { 225 | $wanted_digest = 226 | OAuth::get_validation_code_digest($user_id, $user_name, $expires_at, $client_id, $redirect_uri); 227 | } else if (strcasecmp($type, 'refresh') === 0) { 228 | $wanted_digest = OAuth::get_refresh_token_digest($user_id, $user_name, $expires_at, $client_id); 229 | } else { 230 | throw new \Exception('Unsupported type'); 231 | } 232 | } catch (\Exception $e) { 233 | return array('error' => 'incorrect_client_credentials'); 234 | } 235 | if (Utils::secure_strings_are_equal($digest, $wanted_digest) !== TRUE) { 236 | return array('error' => 'bad_verification_code'); 237 | } 238 | $access_token_expires_at = $now + OAUTH_ACCESS_TOKEN_EXPIRATION; 239 | $access_token = OAUTH_ACCESS_TOKEN_SCOPE . OAUTH_GLUE . $client_id . OAUTH_GLUE . 240 | $user_id . OAUTH_GLUE . $user_name . OAUTH_GLUE . $access_token_expires_at . OAUTH_GLUE . 241 | OAuth::get_access_token_digest($user_id, $user_name, $access_token_expires_at, $client_id); 242 | 243 | $refresh_token_expires_at = $now + OAUTH_REFRESH_TOKEN_EXPIRATION; 244 | $refresh_token = OAUTH_REFRESH_TOKEN_SCOPE . OAUTH_GLUE . 245 | $user_id . OAUTH_GLUE . $user_name . OAUTH_GLUE . $refresh_token_expires_at . OAUTH_GLUE . 246 | OAuth::get_refresh_token_digest($user_id, $user_name, $refresh_token_expires_at, $client_id); 247 | 248 | $args = array('access_token' => $access_token, 249 | 'refresh_token' => $refresh_token, 250 | 'expires_in' => OAUTH_ACCESS_TOKEN_EXPIRATION); 251 | if (!empty($state)) { 252 | $args['state'] = $state; 253 | } 254 | Scribe::log('accounts', array('event' => 'logged in through oauth', 255 | 'event_data' => 256 | array('client_id' => $client_id, 257 | 'type' => $type))); 258 | return $args; 259 | } 260 | 261 | static function logout() { 262 | $oauth_client_id = Auth::get_oauth_client_id(); 263 | if (empty($oauth_client_id)) { 264 | return array('return_code' => -1, 265 | 'error_message' => 'Forbidden'); 266 | } 267 | Auth::logout(); 268 | Scribe::log('accounts', array('event' => 'logged out through oauth', 269 | 'event_data' => 270 | array('client_id' => $oauth_client_id)) 271 | ); 272 | return array('return_code' => 1, 273 | 'error_message' => ''); 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /app/lib/class.oauth.inc.php: -------------------------------------------------------------------------------- 1 | '); 6 | define('OAUTH_CODE_EXPIRATION', 5 * 60); 7 | define('OAUTH_REFRESH_TOKEN_SCOPE', 'rSP'); 8 | define('OAUTH_REFRESH_TOKEN_SECRET_KEY', ''); 9 | define('OAUTH_REFRESH_TOKEN_EXPIRATION', 365 * 86400); 10 | define('OAUTH_ACCESS_TOKEN_SCOPE', 'aSP'); 11 | define('OAUTH_ACCESS_TOKEN_SECRET_KEY', ''); 12 | define('OAUTH_ACCESS_TOKEN_EXPIRATION', 1 * 86400); 13 | define('OAUTH_GLUE', '='); 14 | 15 | class OAuth { 16 | static function get_validation_code_digest($user_id, $user_name, $expires_at, $client_id, $redirect_uri) { 17 | self::check_redirect_uri($client_id, $redirect_uri); 18 | return hash_hmac(OAUTH_DIGEST_METHOD, 19 | OAUTH_VALIDATION_SCOPE . OAUTH_GLUE . 20 | $user_id . OAUTH_GLUE . $user_name . OAUTH_GLUE . 21 | $expires_at . OAUTH_GLUE . 22 | $client_id . OAUTH_GLUE . $redirect_uri, 23 | OAUTH_VALIDATION_SECRET_KEY); 24 | } 25 | 26 | static function get_client_secret($client_id) { 27 | $apps = self::get_apps(); 28 | if (empty($apps[$client_id])) { 29 | throw new \Exception('App to be accessed isn\'t registered any more'); 30 | } 31 | return $apps[$client_id]['okey']; 32 | } 33 | 34 | static function get_refresh_token_digest($user_id, $user_name, $refresh_token_expires_at, $client_id) { 35 | $client_secret = self::get_client_secret($client_id); 36 | 37 | return hash_hmac(OAUTH_DIGEST_METHOD, 38 | OAUTH_REFRESH_TOKEN_SCOPE . OAUTH_GLUE . 39 | $user_id . OAUTH_GLUE . $user_name . OAUTH_GLUE . $refresh_token_expires_at . OAUTH_GLUE . 40 | $client_id . OAUTH_GLUE . $client_secret, 41 | OAUTH_REFRESH_TOKEN_SECRET_KEY); 42 | } 43 | 44 | static function get_access_token_digest($user_id, $user_name, $access_token_expires_at, $client_id) { 45 | $client_secret = self::get_client_secret($client_id); 46 | 47 | return hash_hmac(OAUTH_DIGEST_METHOD, 48 | OAUTH_ACCESS_TOKEN_SCOPE . OAUTH_GLUE . 49 | $user_id . OAUTH_GLUE . $user_name . OAUTH_GLUE . $access_token_expires_at . OAUTH_GLUE . 50 | $client_id . OAUTH_GLUE . $client_secret, 51 | OAUTH_ACCESS_TOKEN_SECRET_KEY); 52 | } 53 | 54 | static function get_apps() { 55 | $ret = array('app_name_1' => 56 | array('okey' => '', 57 | 'uris_rx' => array('#^customappurl://#', 58 | '#^http://www[.]example[.]com(/|$)#')), 59 | 60 | 'app_name_2' => 61 | array('okey' => '', 62 | 'uris_rx' => array('#^http://www[.]example[.]net(/|$)#')), 63 | ); 64 | } 65 | return $ret; 66 | } 67 | 68 | static function check_redirect_uri($client_id, $redirect_uri) { 69 | $apps = self::get_apps(); 70 | if (empty($apps[$client_id])) { 71 | require_once SHARED_LIB_DIR . '/class.scribe.inc.php'; 72 | Scribe::log('security', array('event' => 'unregistered oauth client', 73 | 'event_data' => array 74 | ('client_id' => $client_id, 75 | 'redirect_uri' => $redirect_uri))); 76 | throw new \Exception('Unregistered client'); 77 | } 78 | $app = $apps[$client_id]; 79 | foreach ($app['uris_rx'] as $uri_rx) { 80 | if (preg_match($uri_rx, $redirect_uri)) { 81 | return TRUE; 82 | } 83 | } 84 | require_once SHARED_LIB_DIR . '/class.scribe.inc.php'; 85 | Scribe::log('security', array('event' => 'unauthorized oauth redirection URI', 86 | 'event_data' => array 87 | ('client_id' => $client_id, 88 | 'redirect_uri' => $redirect_uri))); 89 | throw new \Exception('Unauthorized'); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /lib/class.generic_utils.inc.php: -------------------------------------------------------------------------------- 1 | ' . "\n" . 100 | 'window.location.href = "' . addslashes($uri) . '";' . "\n" . 101 | '' . "\n"; 102 | exit; 103 | } 104 | 105 | static function construct_uri_from_base_uri_and_args($params) { 106 | if (empty($params['uri'])) { 107 | throw new \Exception('Empty URI'); 108 | } 109 | $uri = Utils::expand_to_current_uri($params['uri']); 110 | if (strchr($uri, '?') === FALSE) { 111 | $first_param = TRUE; 112 | } else { 113 | $first_param = FALSE; 114 | } 115 | foreach ($params as $key => $value) { 116 | if ($key === 'uri') { 117 | continue; 118 | } 119 | if ($first_param === TRUE) { 120 | $uri .= '?'; 121 | $first_param = FALSE; 122 | } else { 123 | $uri .= '&'; 124 | } 125 | $uri .= urlencode($key) . '=' . urlencode($value); 126 | } 127 | return $uri; 128 | } 129 | 130 | static function redirect_to_with_args($params) { 131 | Utils::redirect_to(Utils::construct_uri_from_base_uri_and_args($params)); 132 | } 133 | 134 | static function http_nocache() { 135 | header('Cache-Control: no-store, private, must-revalidate, ' . 136 | 'proxy-revalidate, ' . 137 | 'post-check=0, pre-check=0, max-age=0, s-maxage=0'); 138 | header('Pragma: no-cache'); 139 | } 140 | 141 | static function http_cache($duration) { 142 | $now = time(); 143 | $last_modified_ts = $now; 144 | $expires_ts = $last_modified_ts + $duration; 145 | 146 | if (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { 147 | $ims_date = @strtotime((string) $_SERVER['HTTP_IF_MODIFIED_SINCE']); 148 | if (!empty($ims_date) && $ims_date <= $now && 149 | $now - $ims_date < $duration) { 150 | header('HTTP/1.1 304 Not Modified'); 151 | exit(0); 152 | } 153 | } 154 | header('Cache-Control: private, must-revalidate, proxy-revalidate, ' . 155 | 'max-age=' . $duration . ', ' . 156 | 's-max-age=' . $duration . ', ' . 157 | 'stale-while-revalidate=' . $duration . ', ' . 158 | 'stale-if-error=86400'); 159 | header('Last-Modified: ' . date('r', $last_modified_ts)); 160 | header('Expires: ' . date('r', $expires_ts)); 161 | header('Pragma: cache'); 162 | } 163 | 164 | static function curl_simple_wrapper($method, $url, $data = array(), 165 | $timeout = CURL_DEFAULT_TIMEOUT, 166 | $headers = array()) { 167 | $ch = curl_init(); 168 | curl_setopt($ch, CURLOPT_URL, $url); 169 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 170 | curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); 171 | curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, CURL_DEFAULT_TIMEOUT); 172 | curl_setopt($ch, CURLOPT_TIMEOUT, CURL_DEFAULT_TIMEOUT); 173 | $headers += array('Expect' => ''); 174 | $curl_headers = array(); 175 | foreach ($headers as $header_name => $header_property) { 176 | array_push($curl_headers, $header_name . ':' . $header_property); 177 | } 178 | curl_setopt($ch, CURLOPT_HTTPHEADER, $curl_headers); 179 | switch (strtoupper($method)) { 180 | case 'GET': 181 | break; 182 | case 'POST': 183 | case 'PUT': 184 | if (is_string($data)) { 185 | curl_setopt($ch, CURLOPT_POSTFIELDS, $data); 186 | } else { 187 | curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); 188 | } 189 | default: 190 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); 191 | } 192 | $ret = curl_exec($ch); 193 | $status = curl_getinfo($ch); 194 | curl_close($ch); 195 | if ($status['http_code'] < 200 || $status['http_code'] >= 300) { 196 | return FALSE; 197 | } 198 | return $ret; 199 | } 200 | 201 | static function secure_strings_are_equal($a, $b) { 202 | $la = strlen($a); 203 | if ($la !== strlen($b) || $la <= 0) { 204 | return FALSE; 205 | } 206 | $res = 0; 207 | do { 208 | $la--; 209 | $res |= ord($a[$la]) ^ ord($b[$la]); 210 | } while ($la != 0); 211 | 212 | return $res === 0; 213 | } 214 | 215 | static function anti_xsrf() { 216 | if (empty($_SERVER['REMOTE_ADDR'])) { 217 | return; 218 | } 219 | if (empty($_SERVER['HTTP_HOST'])) { 220 | die("command-line\n"); 221 | } 222 | if (empty($_POST) || empty($_SERVER['HTTP_REFERER']) || 223 | preg_match('#^http(s)?://([^/]+[.])?(' . 224 | preg_quote($_SERVER['HTTP_HOST']) . 225 | '|' . AUTHORIZED_XSRF_DOMAINS . 226 | ')($|/)#i', $_SERVER['HTTP_REFERER']) > 0) { 227 | return; 228 | } 229 | foreach (array_keys($_POST) as $k) { 230 | unset($_REQUEST[$k]); 231 | } 232 | $_POST = array(); 233 | } 234 | 235 | static function uuid() { 236 | $cstrong = TRUE; 237 | return trim(strtr 238 | (base64_encode 239 | (openssl_random_pseudo_bytes(UUID_KEY_LENGTH, 240 | $cstrong)), '+/=', '-. ') 241 | ); 242 | } 243 | } 244 | 245 | if (!function_exists('N_')) { 246 | function gettext_noop($str) { 247 | return $str; 248 | } 249 | 250 | function N_($str) { 251 | return $str; 252 | } 253 | } 254 | 255 | -------------------------------------------------------------------------------- /lib/class.route.inc.php: -------------------------------------------------------------------------------- 1 | $found_action, 78 | 'found_params' => $found_params); 79 | } 80 | 81 | static function _examine_splitted_paths($params) { 82 | $action = FALSE; 83 | $extra_params = array(); 84 | $splitted_path = $params['splitted_path']; 85 | $route_splitted_path = $params['route_splitted_path']; 86 | $route = $params['route']; 87 | 88 | if (sizeof($splitted_path) !== sizeof($route_splitted_path)) { 89 | return FALSE; 90 | } 91 | $i = 0; 92 | foreach ($route_splitted_path as $scanned_component) { 93 | $component = $splitted_path[$i]; 94 | $i++; 95 | if (($ret = self::_examine_splitted_path_component 96 | (array('scanned_component' => $scanned_component, 97 | 'component' => $component, 98 | 'route' => $route)) 99 | ) === FALSE) { 100 | return FALSE; 101 | } 102 | if (!empty($ret['found_action'])) { 103 | $action = $ret['found_action']; 104 | } 105 | if (!empty($ret['found_params'])) { 106 | $extra_params = array_merge($extra_params, 107 | $ret['found_params']); 108 | } 109 | } 110 | if (empty($action)) { 111 | $action = $route['action']; 112 | } 113 | return array('action' => $action, 114 | 'extra_params' => $extra_params); 115 | } 116 | 117 | static function _init_params() { 118 | $g = $_GET; 119 | $p = $_POST; 120 | $f = $_FILES; 121 | if (MAGIC_QUOTES_ALREADY_DISABLED === FALSE && 122 | get_magic_quotes_gpc()) { 123 | self::strip_slashes_from_user_data($g); 124 | self::strip_slashes_from_user_data($p); 125 | } 126 | self::$action_params = array_merge(self::$action_params, $g); 127 | self::$action_params = array_merge(self::$action_params, $p); 128 | foreach ($_FILES as $param_name => $file) { 129 | if (!empty($file['tmp_name'])) { 130 | $file_content = @file_get_contents($file['tmp_name']); 131 | if (!empty($content)) { 132 | self::$action_params[$param_name] = $file_content; 133 | } 134 | unset($file_content); 135 | } 136 | } 137 | } 138 | 139 | static function _handle_put_data_multipart($boundary) { 140 | $data = file_get_contents("php://input"); 141 | if (empty($data)) { 142 | return; 143 | } 144 | $p = 0; 145 | while (($bpos = strpos($data, $boundary . "\r\n", $p)) !== FALSE) { 146 | $p = $bpos + strlen($boundary . "\r\n"); 147 | if (preg_match('~^Content-Disposition:\s*form-data;\s*name="(.+?)"~', 148 | substr($data, $p), $matches) <= 0 || 149 | ($var = $matches[1]) === '') { 150 | break; 151 | } 152 | $p += strlen($matches[0]); 153 | if (($p = strpos($data, "\r\n\r\n", $p)) === FALSE) { 154 | break; 155 | } 156 | $p += strlen("\r\n\r\n"); 157 | $eop = strpos($data, $boundary, $p); 158 | if ($eop === FALSE) { 159 | $value = substr($data, $p); 160 | } else { 161 | $value = @substr($data, $p, $eop - $p - 4); 162 | } 163 | if (MAGIC_QUOTES_ALREADY_DISABLED === FALSE && 164 | get_magic_quotes_gpc()) { 165 | $_POST[$var] = addslashes($value); 166 | } else { 167 | $_POST[$var] = $value; 168 | } 169 | $p = $eop; 170 | } 171 | } 172 | 173 | static function _handle_put_data_urlencoded() { 174 | $data = file_get_contents("php://input"); 175 | if (empty($data)) { 176 | return; 177 | } 178 | foreach (explode('&', $data) as $d) { 179 | @list($var, $value) = explode('=', $d); 180 | $var = @urldecode($var); 181 | if (empty($var)) { 182 | continue; 183 | } 184 | if (MAGIC_QUOTES_ALREADY_DISABLED === FALSE && 185 | get_magic_quotes_gpc()) { 186 | $_POST[$var] = addslashes(@urldecode($value)); 187 | } else { 188 | $_POST[$var] = @urldecode($value); 189 | } 190 | $_REQUEST[$var] = $_POST[$var]; 191 | } 192 | } 193 | 194 | static function _handle_put_data() { 195 | if (strcasecmp($_SERVER['REQUEST_METHOD'], 'PUT') !== 0 || 196 | ($content_type = @$_SERVER['CONTENT_TYPE']) === '' || 197 | @$_SERVER['CONTENT_LENGTH'] <= 0) { 198 | return FALSE; 199 | } 200 | $matches = array(); 201 | if (preg_match('~/x-www-form-urlencoded~', 202 | $content_type, $matches) > 0) { 203 | self::_handle_put_data_urlencoded(); 204 | return TRUE; 205 | } 206 | if (preg_match('~^multipart/form-data;\s*boundary=(.+)$~', 207 | $content_type, $matches) <= 0 || 208 | ($boundary = $matches[1]) === '') { 209 | return TRUE; 210 | } 211 | self::_handle_put_data_multipart($boundary); 212 | 213 | return TRUE; 214 | } 215 | 216 | static function _handle_json_encoded_data() { 217 | if (empty($_SERVER['CONTENT_TYPE'])) { 218 | return FALSE; 219 | } 220 | $content_type = (string) $_SERVER['CONTENT_TYPE']; 221 | if (preg_match('~/json($|\\s*;)~', $content_type) <= 0) { 222 | return FALSE; 223 | } 224 | $json_data = file_get_contents("php://input"); 225 | if (empty($json_data)) { 226 | return TRUE; 227 | } 228 | $obj_data = @json_decode($json_data); 229 | if (empty($obj_data)) { 230 | return TRUE; 231 | } 232 | $data = (array) $obj_data; 233 | foreach ($data as $var => $value) { 234 | if (MAGIC_QUOTES_ALREADY_DISABLED === FALSE && 235 | get_magic_quotes_gpc()) { 236 | $_POST[$var] = addslashes($value); 237 | } else { 238 | $_POST[$var] = $value; 239 | } 240 | $_REQUEST[$var] = $_POST[$var]; 241 | } 242 | return TRUE; 243 | } 244 | 245 | static function _output($content_type, $encoded_content) { 246 | header('Content-Type: ' . $content_type . '; charset=utf-8'); 247 | header('Content-Length: ' . strlen($encoded_content)); 248 | echo $encoded_content; 249 | flush(); 250 | } 251 | 252 | public 253 | 254 | static function map_connect($params) { 255 | $extra_params = $params; 256 | foreach (array('path', 'controller', 'action', 'method') as $key) { 257 | unset($extra_params[$key]); 258 | } 259 | if (empty($params['method'])) { 260 | $params['method'] = 'GET'; 261 | } 262 | array_push(self::$routes, 263 | array('controller' => $params['controller'], 264 | 'path' => $params['path'], 265 | 'splitted_path' => explode('/', $params['path']), 266 | 'method' => strtoupper($params['method']), 267 | 'action' => $params['action'], 268 | 'extra_params' => $extra_params)); 269 | } 270 | 271 | static function map_resources($params) { 272 | $resource_name = $params['resource']; 273 | if (empty($params['path_prefix'])) { 274 | $path_prefix = '/'; 275 | } else { 276 | $path_prefix = $params['path_prefix']; 277 | } 278 | self::map_connect 279 | (array('controller' => $resource_name, 280 | 'path' => $path_prefix . $resource_name . '/new', 281 | 'method' => 'GET', 282 | 'action' => 'new')); 283 | self::map_connect 284 | (array('controller' => $resource_name, 285 | 'path' => $path_prefix . $resource_name . '/:id;edit', 286 | 'method' => 'GET', 287 | 'action' => 'edit')); 288 | self::map_connect 289 | (array('controller' => $resource_name, 290 | 'path' => $path_prefix . $resource_name . '/:id', 291 | 'method' => 'GET', 292 | 'action' => 'show')); 293 | self::map_connect 294 | (array('controller' => $resource_name, 295 | 'path' => $path_prefix . $resource_name . '/:id', 296 | 'method' => 'PUT', 297 | 'action' => 'update')); 298 | self::map_connect 299 | (array('controller' => $resource_name, 300 | 'path' => $path_prefix . $resource_name . '/:id', 301 | 'method' => 'DELETE', 302 | 'action' => 'delete')); 303 | self::map_connect 304 | (array('controller' => $resource_name, 305 | 'path' => $path_prefix . $resource_name, 306 | 'method' => 'POST', 307 | 'action' => 'create')); 308 | self::map_connect 309 | (array('controller' => $resource_name, 310 | 'path' => $path_prefix . $resource_name, 311 | 'method' => 'GET', 312 | 'action' => 'index')); 313 | } 314 | 315 | static function find_route($params) { 316 | $response_format = DEFAULT_CONTROLLERS_FORMAT; 317 | $method = $params['method']; 318 | $path = $params['path']; 319 | if ($path !== '/' && substr($path, -1) === '/') { 320 | $path = substr($path, 0, strlen($path) - 1); 321 | } 322 | $matches = array(); 323 | if ((preg_match('/^(.+)[.]([a-z0-9-]+)$/i', $path, $matches)) > 0) { 324 | $path = $matches[1]; 325 | $response_format = $matches[2]; 326 | } 327 | unset($matches); 328 | $splitted_path = explode('/', $path); 329 | $sizeof_splitted_path = sizeof($splitted_path); 330 | 331 | $ret = FALSE; 332 | foreach (self::$routes as $route) { 333 | if (strcasecmp($route['method'], $method) !== 0) { 334 | continue; 335 | } 336 | if (($ret = self::_examine_splitted_paths 337 | (array('route' => $route, 338 | 'splitted_path' => $splitted_path, 339 | 'route_splitted_path' => $route['splitted_path'])) 340 | ) === FALSE) { 341 | continue; 342 | } 343 | break; 344 | } 345 | if ($ret === FALSE) { 346 | return FALSE; 347 | } 348 | return array('route' => $route, 349 | 'action' => $ret['action'], 350 | 'response_format' => $response_format, 351 | 'extra_params' => $ret['extra_params']); 352 | } 353 | 354 | static function strip_slashes_from_user_data(&$array) { 355 | foreach($array as $k => $v) { 356 | if (is_array($v)) { 357 | self::strip_slashes_from_user_data($array[$k]); 358 | continue; 359 | } 360 | $array[$k] = stripslashes($v); 361 | } 362 | } 363 | 364 | static function trusted_binary_params($key) { 365 | if (!isset(self::$action_params[$key])) { 366 | return NULL; 367 | } 368 | return self::$action_params[$key]; 369 | } 370 | 371 | static function trusted_params($key) { 372 | if (!isset(self::$action_params[$key])) { 373 | return NULL; 374 | } 375 | $value = self::$action_params[$key]; 376 | if (FILTER_BOGUS_UTF8 === TRUE && 377 | mb_check_encoding($value, 'UTF-8') === FALSE) { 378 | return NULL; 379 | } 380 | return $value; 381 | } 382 | 383 | static function params($key) { 384 | if (!isset(self::$action_params[$key])) { 385 | return NULL; 386 | } 387 | $value = self::$action_params[$key]; 388 | if (FILTER_BOGUS_UTF8 === TRUE && 389 | mb_check_encoding($value, 'UTF-8') === FALSE) { 390 | return NULL; 391 | } 392 | if (FILTER_HTML_TAGS === FALSE) { 393 | return $value; 394 | } 395 | $value_ = strtr($value, '<>', ' '); 396 | if (isset($_SERVER['TEST']) && $value_ !== $value) { 397 | fatal(); 398 | } 399 | return trim($value_); 400 | } 401 | 402 | static function run() { 403 | if (empty($_SERVER['HTTP_HOST'])) { 404 | die("\\o/\n"); 405 | } 406 | $method = $_SERVER['REQUEST_METHOD']; 407 | $path = ''; 408 | if (isset($_SERVER['PATH_INFO'])) { 409 | $path = $_SERVER['PATH_INFO']; 410 | } 411 | $ret = self::find_route(array('method' => $method, 412 | 'path' => $path)); 413 | if ($ret === FALSE) { 414 | @header('HTTP/1.0 404 Not Found'); 415 | die('

404 - Introuvable.

' . "\n"); 416 | } 417 | if (self::_handle_json_encoded_data() === FALSE) { 418 | self::_handle_put_data(); 419 | } 420 | self::_init_params(); 421 | self::$action_params = array_merge(self::$action_params, 422 | $ret['extra_params']); 423 | $route = $ret['route']; 424 | $action = $ret['action']; 425 | $response_format = $ret['response_format']; 426 | $controller = $route['controller']; 427 | $controller_file = self::$controllers_path . 428 | preg_replace('/[^a-z0-9-]/i', '_', $controller) . 429 | self::$controller_suffix; 430 | if (file_exists($controller_file) === FALSE) { 431 | @header('HTTP/1.0 503 Service Unavailable'); 432 | die('

503 - Nonexistent controller.

' . "\n"); 433 | } 434 | require_once $controller_file; 435 | if (is_callable(array('Controller', $action)) === FALSE) { 436 | @header('HTTP/1.0 501 Not implemented'); 437 | die('

501 - Nonexistent action.

' . "\n"); 438 | } 439 | $ret = TRUE; 440 | try { 441 | $ret = call_user_func(array('Controller', $action), 442 | self::params('id')); 443 | } catch (Exception $e) { 444 | throw $e; 445 | } 446 | if ($ret === FALSE) { 447 | @header('HTTP/1.0 500 Internal Server Error'); 448 | die('

500 - Action sent a generic error

' . "\n"); 449 | } 450 | if (is_string($ret)) { 451 | if (ENABLE_FRAGMENTS_CACHING) { 452 | $known_fragments = (string) params('_fragments'); 453 | $ret = FragmentCache::crunch($ret, $known_fragments); 454 | } 455 | echo $ret; 456 | return TRUE; 457 | } 458 | if (!is_array($ret)) { 459 | @header('HTTP/1.0 500 Internal Server Error'); 460 | die('

500 - Invalid response type

' . "\n"); 461 | } 462 | switch (strtolower($response_format)) { 463 | case 'json': 464 | self::_output('application/json', json_encode($ret)); 465 | return TRUE; 466 | case 'jsonp': 467 | $jsonp_cb = (string) params('jsonp'); 468 | if (strstr($jsonp_cb, JSONP_CB_REQUIRED_SUBSTR) === FALSE || 469 | preg_match('/^[a-z_]+[a-z0-9_.]*$/i', $jsonp_cb) <= 0) { 470 | header('HTTP/1.0 400 Bad Request'); 471 | echo '

400 - Invalid JSON-P callback name

'; 472 | die(); 473 | } 474 | self::_output('text/javascript', 475 | $jsonp_cb . '(' . json_encode($ret) . ');'); 476 | return TRUE; 477 | case 'html': 478 | if (empty($_SERVER['PROD'])) { 479 | self::_output('text/plain', htmlentities(serialize($ret))); 480 | return TRUE; 481 | } 482 | break; 483 | case 'igb': 484 | if (function_exists('igbinary_serialize')) { 485 | self::_output('application/igbinary-serialized', 486 | igbinary_serialize($ret)); 487 | return TRUE; 488 | } 489 | break; 490 | case 'phpser': 491 | self::_output('application/php-serialized', serialize($ret)); 492 | return TRUE; 493 | } 494 | header('HTTP/1.0 500 Internal Server Error'); 495 | header('Content-Type: text/html; charset=UTF-8'); 496 | echo '

500 - Unknown output format (' . 497 | htmlentities($response_format) . ').

' . "\n"; 498 | die(htmlentities('[' . $_SERVER['REQUEST_METHOD'] . '] [' . 499 | $_SERVER['HTTP_HOST'] . '] [' . 500 | $_SERVER['REQUEST_URI'] . ']') . "\n"); 501 | /* NOTREACHED */ 502 | return FALSE; 503 | } 504 | } 505 | 506 | class _FragmentCacheReplacer { 507 | var $fragments = array(); 508 | 509 | function __construct($known_fragments) { 510 | if (empty($known_fragments)) { 511 | return; 512 | } 513 | foreach (explode(' ', $known_fragments) as $fragment) { 514 | if (empty($fragment)) { 515 | continue; 516 | } 517 | $fragment_array = explode('-', $fragment, 2); 518 | if (count($fragment_array) < 2) { 519 | continue; 520 | } 521 | list($fragment_name, $fragment_digest) = $fragment_array; 522 | if (empty($fragment_name) || empty($fragment_digest)) { 523 | continue; 524 | } 525 | $this->fragments[$fragment_name] = $fragment_digest; 526 | } 527 | } 528 | 529 | function replace_fragment($matches) { 530 | $fragment_name = $matches[1]; 531 | $fragment_content = $matches[2]; 532 | assert(htmlspecialchars($fragment_name) === $fragment_name); 533 | $digest = md5($fragment_content); 534 | if (isset($this->fragments[$fragment_name]) && 535 | $digest === $this->fragments[$fragment_name]) { 536 | return ""; 537 | } 538 | return "" . 539 | "$fragment_content"; 540 | } 541 | } 542 | 543 | class FragmentCache { 544 | const FRAGMENT_RX = 545 | '#(.+?)#msi'; 546 | 547 | static function crunch($document, $known_fragments) { 548 | $obj_fragments = new _FragmentCacheReplacer($known_fragments); 549 | $crunched_document = preg_replace_callback 550 | (self::FRAGMENT_RX, 551 | array($obj_fragments, 'replace_fragment'), 552 | $document); 553 | unset($obj_fragments); 554 | 555 | return $crunched_document; 556 | } 557 | } 558 | 559 | function params($key) { 560 | return Route::params($key); 561 | } 562 | 563 | function trusted_params($key) { 564 | return Route::trusted_params($key); 565 | } 566 | 567 | function trusted_binary_params($key) { 568 | return Route::trusted_binary_params($key); 569 | } 570 | -------------------------------------------------------------------------------- /lib/class.scribe.inc.php: -------------------------------------------------------------------------------- 1 | $category, 'message' => $message)); 51 | $messages = array($log_entry); 52 | $socket = new \TSocket(SCRIBE_HOST, SCRIBE_PORT, FALSE); 53 | $transport = new \TFramedTransport($socket); 54 | $protocol = new \TBinaryProtocolAccelerated($transport, FALSE, FALSE); 55 | $client = new \scribeClient($protocol, $protocol); 56 | $transport->open(); 57 | $client->send_log($messages); 58 | $transport->close(); 59 | } catch (\TException $e) { 60 | return FALSE; 61 | } 62 | return TRUE; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/class.sky_smarty.inc.php: -------------------------------------------------------------------------------- 1 | setDebugging(TRUE); 36 | $this->setForceCompile(TRUE); 37 | } else { 38 | $this->setDebugging(FALSE); 39 | } 40 | $this->setErrorReporting(E_ALL & ~ (E_USER_NOTICE | E_NOTICE)); 41 | $this->setCaching(FALSE); 42 | $this->setTemplateDir(APP_SMARTY_TEMPLATES_DIR); 43 | $this->setCompileDir(APP_SMARTY_COMPILE_DIR); 44 | $this->setConfigDir(APP_SMARTY_CONFIG_DIR); 45 | $this->addPluginsDir(APP_SMARTY_PLUGINS_DIR); 46 | 47 | $this->config_vars['STATIC_URL'] = htmlspecialchars(STATIC_URL); 48 | $this->config_vars['DYNAMIC_URL'] = htmlspecialchars(DYNAMIC_URL); 49 | $this->config_vars['JS_VERSION'] = htmlspecialchars(JS_VERSION); 50 | $this->config_vars['CSS_VERSION'] = htmlspecialchars(CSS_VERSION); 51 | $this->config_vars['IMAGES_VERSION'] = htmlspecialchars(IMAGES_VERSION); 52 | $this->config_vars['DEBUG_MODE'] = (bool) !empty($_COOKIE['debug']); 53 | 54 | $this->assign('current_uri', Utils::get_current_uri()); 55 | 56 | return $this; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/errors.inc.php: -------------------------------------------------------------------------------- 1 | '); 13 | 14 | $custom_error_handler_redirection = null; 15 | 16 | function _custom_error_handler_antibomb() { 17 | $now = time(); 18 | 19 | $antibomb_file = _CUSTOM_ERROR_HANDLER_ANTIBOMB_FILE_PREFIX; 20 | if (!empty($_SERVER['SCRIPT_FILENAME'])) { 21 | $antibomb_file .= md5($_SERVER['SCRIPT_FILENAME']); 22 | } 23 | if (($st = @stat($antibomb_file)) === FALSE || 24 | ($mtime = $st['mtime']) <= 0 || $mtime > $now || 25 | ($now - $mtime) > _CUSTOM_ERROR_HANDLER_ANTIBOMB_INTERVAL) { 26 | @touch($antibomb_file); 27 | return 0; 28 | } 29 | return -1; 30 | } 31 | 32 | function _custom_error_handler_html($errno, $errstr, $errfile, $errline, 33 | $trace, $bt_dump, $server_dump) { 34 | $ret = << 37 | 38 | 39 | 40 | 41 | Erreur 42 | 43 | 74 | 75 | 76 | 77 | EOF 78 | ; 79 | $ret .= '
' . "\n"; 80 | $ret .= '

' . "\n"; 81 | $ret .= ' Erreur ['. htmlentities($errno) . '] :
' . "\n"; 82 | $ret .= ' ' . htmlentities($errstr) . "\n"; 83 | $ret .= '

' . "\n"; 84 | $ret .= '
' . "\n"; 85 | $ret .= '

Location

' . "\n"; 86 | $ret .= '

' . "\n"; 87 | $ret .= ' File: ' . htmlentities($errfile) . '' . 88 | '
' . "\n"; 89 | $ret .= ' Line: ' . htmlentities($errline) . '' . "\n"; 90 | $ret .= '

' . "\n"; 91 | $ret .= '
' . "\n"; 92 | $ret .= '
' . "\n"; 93 | $ret .= '

Calls chain

' . "\n"; 94 | $ret .= '

' . "\n"; 95 | $ret .= ' ' . htmlentities($trace) . "\n"; 96 | $ret .= '

' . "\n"; 97 | $ret .= '
' . "\n"; 98 | $ret .= '
' . "\n"; 99 | $ret .= '

Stack trace

' . "\n"; 100 | $ret .= '
' . "\n";    
101 |     $ret .= htmlentities($bt_dump);
102 |     $ret .= '      
' . "\n"; 103 | $ret .= '
' . "\n"; 104 | $ret .= '
' . "\n"; 105 | $ret .= '

Environment

' . "\n"; 106 | $ret .= '
' . "\n";
107 |     $ret .= htmlentities($server_dump);
108 |     $ret .= '      
' . "\n"; 109 | $ret .= '
' . "\n"; 110 | $ret .= '
' . "\n"; 111 | $ret .= << 113 | 114 | 115 | EOF 116 | ; 117 | 118 | return $ret; 119 | } 120 | 121 | function custom_error_handler_($errno, $errstr, $errfile, $errline, $bt = NULL) 122 | { 123 | global $custom_error_handler_redirection; 124 | 125 | if (($errno == E_NOTICE || $errno == E_USER_NOTICE) && 126 | ONERROR_REPORT_EVEN_NOTICES == FALSE) { 127 | return; 128 | } 129 | if (($errno & error_reporting()) === 0 && 130 | ONERROR_REPORT_EVEN_IGNORED == FALSE) { 131 | return; 132 | } 133 | if ((ONERROR_SHOW | ERRORNOT_ENABLED) == FALSE) { 134 | return; 135 | } 136 | if (function_exists('skycache_no_store')) { 137 | skycache_no_store(); 138 | } 139 | $trace = ''; 140 | if (empty($bt)) { 141 | $bt = debug_backtrace(); 142 | array_shift($bt); 143 | } 144 | foreach ($bt as $t) { 145 | if (!is_array($t) || !isset($t['function'])) { 146 | continue; 147 | } 148 | $trace = $t['function'] . '() -> ' . $trace; 149 | } 150 | $trace .= '*KABOOM*'; 151 | $bt_dump = addcslashes(print_r($bt, TRUE), "\\\0\r"); 152 | $server_dump = addcslashes(print_r($_SERVER, TRUE), "\\\0\r"); 153 | $html = _custom_error_handler_html 154 | ($errno, $errstr, $errfile, $errline, $trace, $bt_dump, $server_dump); 155 | if (ONERROR_SHOW != FALSE) { 156 | print $html; 157 | } else { 158 | if (empty($custom_error_handler_redirection)) { 159 | $custom_error_handler_redirection = ONERROR_URI_TEMPORARY; 160 | } 161 | if (isset($_SERVER['HTTP_HOST']) && 162 | preg_match('|^\w+://.|', $custom_error_handler_redirection) <= 0) { 163 | $custom_error_handler_redirection = 'http://' . 164 | rawurlencode($_SERVER['HTTP_HOST']) . $custom_error_handler_redirection; 165 | } 166 | @header('Location: ' . $custom_error_handler_redirection); 167 | print << 171 | 172 | 173 | 174 | EOF 175 | ; 176 | print ' ' . "\n"; 178 | print << 181 | 182 | ... 183 | 184 | 185 | 186 |
187 | ... 188 |
189 | 190 | 191 | 192 | EOF 193 | ; 194 | } 195 | if (_custom_error_handler_antibomb() !== 0) { 196 | die(); 197 | } 198 | 199 | if (ERRORNOT_ENABLED !== TRUE) { 200 | die(); 201 | } 202 | require_once 'HTTP/Request2.php'; 203 | require_once APP_LIB_DIR . '/ErrorNot/errornot.php'; 204 | 205 | $errornot = new Services_ErrorNot(ERRORNOT_URI, ERRORNOT_API_KEY); 206 | 207 | $en_bt = '

' . nl2br(htmlspecialchars($errstr)) . '

'; 208 | $en_bt .= '
    '; 209 | 210 | foreach ($bt as $trace) { 211 | if (empty($trace['file']) || empty($trace['line'])) { 212 | continue; 213 | } 214 | if (strstr(__FILE__, $trace['file']) !== FALSE) { 215 | continue; 216 | } 217 | $en_bt .= '
  • '; 218 | $en_bt .= 219 | 'File: ' . nl2br(htmlspecialchars($trace['file']) . "\n") . 220 | 'Line: ' . nl2br(htmlspecialchars($trace['line']) . "\n"); 221 | if ($trace['function'] !== 'custom_error_handler') { 222 | $en_bt .= 'Function: ' . 223 | nl2br(htmlspecialchars($trace['function']) . "()\n"); 224 | } 225 | $en_bt .= '
  • '; 226 | } 227 | $en_bt .= '
'; 228 | $en_bt = str_replace("\n", '', $en_bt); 229 | if (!empty($_SERVER['REMOTE_ADDR'])) { 230 | $uri = 'http://' . rawurlencode($_SERVER['HTTP_HOST']) . 231 | $_SERVER['REQUEST_URI']; 232 | } else { 233 | $uri = '(commandline)'; 234 | } 235 | $errornot->notify(substr($errstr, 0, 100), NULL, $en_bt, 236 | array('request' => 237 | array('uri' => $uri, 238 | 'method' => @$_SERVER['REQUEST_METHOD'], 239 | 'post' => $_POST, 'get' => $_GET, 240 | 'cookies' => $_COOKIE), 241 | 'params' => 242 | array('svn_user' => @$_SERVER['SVN_USER']) 243 | ), 244 | $_SERVER); 245 | die(); 246 | } 247 | 248 | function custom_error_handler($errno, $errstr, $errfile, $errline) { 249 | return custom_error_handler_($errno, $errstr, $errfile, $errline); 250 | } 251 | 252 | function custom_error_handler_set_redirect($url) { 253 | global $custom_error_handler_redirection; 254 | 255 | $custom_error_handler_redirection = $url; 256 | } 257 | 258 | function fatal($message = 'Incoherence') { 259 | trigger_error($message, E_USER_ERROR); 260 | die(); 261 | } 262 | 263 | function show_or_mail_exception($e) { 264 | if (!($e instanceof Exception)) { 265 | fatal(); 266 | } 267 | custom_error_handler_(E_USER_ERROR, 268 | get_class($e) . ': ' . $e->getMessage(), 269 | $e->getFile(), $e->getLine(), 270 | $e->getTrace()); 271 | } 272 | 273 | function custom_exception_handler($e) { 274 | return show_or_mail_exception($e); 275 | } 276 | 277 | set_error_handler('custom_error_handler'); 278 | set_exception_handler('custom_exception_handler'); 279 | 280 | --------------------------------------------------------------------------------