php - saber - short_open_tag off
Cómo saber si está utilizando HTTPS sin $_SERVER (23)
He visto muchos tutoriales en línea que dicen que debes verificar $_SERVER[''HTTPS'']
si la conexión del servidor está asegurada con HTTPS. Mi problema es que en algunos de los servidores que uso, $_SERVER[''HTTPS'']
es una variable indefinida que da como resultado un error. ¿Hay alguna otra variable que pueda verificar que siempre deba definirse?
Para que quede claro, actualmente estoy usando este código para resolver si se trata de una conexión HTTPS:
if(isset($_SERVER[''HTTPS''])) {
if ($_SERVER[''HTTPS''] == "on") {
$secure_connection = true;
}
}
¿Qué piensas de esto?
if (isset($_SERVER[''HTTPS'']) && !empty($_SERVER[''HTTPS'']) && $_SERVER[''HTTPS''] != ''off'')
$scheme = ''https'';
else
$scheme = ''http'';
Acabo de tener un problema donde estaba ejecutando el servidor usando Apache mod_ssl, pero un phpinfo () y un var_dump ($ _SERVER) mostraron que PHP todavía piensa que estoy en el puerto 80.
Aquí está mi solución para cualquier persona con el mismo problema ...
<VirtualHost *:443>
SetEnv HTTPS on
DocumentRoot /var/www/vhost/scratch/content
ServerName scratch.example.com
</VirtualHost>
La línea que vale la pena observar es la línea SetEnv. Con esto en su lugar y después de un reinicio, debe tener la variable de entorno HTTPS que siempre soñó
Agregaría un filtro global para garantizar que todo lo que estoy verificando sea correcto;
function isSSL() {
$https = filter_input(INPUT_SERVER, ''HTTPS'');
$port = filter_input(INPUT_SERVER, ''SERVER_PORT'');
if ($https) {
if ($https == 1) {
return true;
} elseif ($https == ''on'') {
return true;
}
} elseif ($port == ''443'') {
return true;
}
return false;
}
Aquí hay una función reutilizable que he estado usando por un tiempo. HTH.
Nota: El valor de HTTPS_PORT (que es una constante personalizada en mi código) puede variar según su entorno, por ejemplo, puede ser 443 u 81.
/**
* Determine if this is a secure HTTPS connection
*
* @return bool True if it is a secure HTTPS connection, otherwise false.
*/
function isSSL()
{
if (isset($_SERVER[''HTTPS''])) {
if ($_SERVER[''HTTPS''] == 1) {
return true;
} elseif ($_SERVER[''HTTPS''] == ''on'') {
return true;
}
} elseif ($_SERVER[''SERVER_PORT''] == HTTPS_PORT) {
return true;
}
return false;
}
Chacha, según la documentación de PHP: "Establezca un valor no vacío si el script se consultó a través del protocolo HTTPS". Por lo tanto, su sentencia if allí devolverá false en muchos casos donde HTTPS está activado. Deberá verificar que $_SERVER[''HTTPS'']
exista y que no esté vacío. En los casos en que HTTPS no está configurado correctamente para un servidor determinado, puede intentar comprobar si $_SERVER[''SERVER_PORT''] == 443
.
Pero tenga en cuenta que algunos servidores también establecerán $_SERVER[''HTTPS'']
en un valor no vacío, así que asegúrese de verificar también esta variable.
Referencia: Documentación para $_SERVER
y $HTTP_SERVER_VARS
[obsoleta]
El único método confiable es el descrito por Igor M.
$pv_URIprotocol = isset($_SERVER["HTTPS"]) ? (($_SERVER["HTTPS"]==="on" || $_SERVER["HTTPS"]===1 || $_SERVER["SERVER_PORT"]===$pv_sslport) ? "https://" : "http://") : (($_SERVER["SERVER_PORT"]===$pv_sslport) ? "https://" : "http://");
Considere lo siguiente: Está usando nginx con fastcgi, de forma predeterminada (debian, ubuntu) fastgi_params contiene directiva:
fastcgi_param HTTPS $ https;
si NO está utilizando SSL, se traduce como valor vacío, no como ''apagado'', no como 0 y está condenado.
http://unpec.blogspot.cz/2013/01/nette-nginx-php-fpm-redirect.html
En mi servidor (Ubuntu 14.10, Apache 2.4, php 5.5), la variable $_SERVER[''HTTPS'']
no está configurada cuando el script php se carga a través de https. No sé lo que está mal. Pero las siguientes líneas en el archivo .htaccess
corrigen este problema:
RewriteEngine on
RewriteCond %{HTTPS} =on [NC]
RewriteRule .* - [E=HTTPS:on,NE]
Esto siempre debería funcionar incluso cuando $_SERVER[''HTTPS'']
no está definido:
function isSecure() {
return
(!empty($_SERVER[''HTTPS'']) && $_SERVER[''HTTPS''] !== ''off'')
|| $_SERVER[''SERVER_PORT''] == 443;
}
El código es compatible con IIS.
De la documentación de PHP.net y comentarios de los usuarios :
1) Establezca un valor no vacío si el script se consultó a través del protocolo HTTPS.
2) Tenga en cuenta que al usar ISAPI con IIS, el valor será "desactivado" si la solicitud no se realizó a través del protocolo HTTPS. (Se informó el mismo comportamiento para IIS7 que ejecuta PHP como una aplicación Fast-CGI).
Además, es posible que los servidores Apache 1.x (e instalaciones rotas) no tengan definido $_SERVER[''HTTPS'']
incluso si se conectan de forma segura. Aunque no está garantizado, las conexiones en el puerto 443 son, por convention , probablemente utilizando enchufes seguros , de ahí la verificación de puerto adicional.
Esto también funciona cuando $_SERVER[''HTTPS'']
no está definido
if( (!empty($_SERVER[''HTTPS'']) && $_SERVER[''HTTPS''] != ''off'') || $_SERVER[''SERVER_PORT''] == 443 ){
//enable secure connection
}
Hacer mi propia función al leer todas las publicaciones anteriores:
public static function isHttps()
{
if (array_key_exists("HTTPS", $_SERVER) && ''on'' === $_SERVER["HTTPS"]) {
return true;
}
if (array_key_exists("SERVER_PORT", $_SERVER) && 443 === (int)$_SERVER["SERVER_PORT"]) {
return true;
}
if (array_key_exists("HTTP_X_FORWARDED_SSL", $_SERVER) && ''on'' === $_SERVER["HTTP_X_FORWARDED_SSL"]) {
return true;
}
if (array_key_exists("HTTP_X_FORWARDED_PROTO", $_SERVER) && ''https'' === $_SERVER["HTTP_X_FORWARDED_PROTO"]) {
return true;
}
return false;
}
La forma más corta que estoy usando:
$secure_connection = !empty($_SERVER[''HTTPS'']);
Si se usa https, entonces $ secure_connection es verdadero.
La respuesta REAL: listo para copiar y pegar en una secuencia de comandos [config]
/* configuration settings; X=edit may 10th ''11 */ $pv_sslport=443; /* for it might be different, as also Gabriel Sosa stated */ $pv_serverport=80; /* X */ $pv_servername="mysite.com"; /* X */ /* X appended after correction by Michael Kopinsky */ if(!isset($_SERVER["SERVER_NAME"]) || !$_SERVER["SERVER_NAME"]) { if(!isset($_ENV["SERVER_NAME"])) { getenv("SERVER_NAME"); // Set to env server_name $_SERVER["SERVER_NAME"]=$_ENV["SERVER_NAME"]; } } if(!$_SERVER["SERVER_NAME"]) ( /* X server name still empty? ... you might set $_SERVER["SERVER_NAME"]=$pv_servername; */ } if(!isset($_SERVER["SERVER_PORT"]) || !$_SERVER["SERVER_PORT"]) { if(!isset($_ENV["SERVER_PORT"])) { getenv("SERVER_PORT"); $_SERVER["SERVER_PORT"]=$_ENV["SERVER_PORT"]; } } if(!$_SERVER["SERVER_PORT"]) ( /* X server port still empty? ... you might set $_SERVER["SERVER_PORT"]=$pv_serverport; */ } $pv_URIprotocol = isset($_SERVER["HTTPS"]) ? (($_SERVER["HTTPS"]==="on" || $_SERVER["HTTPS"]===1 || $_SERVER["SERVER_PORT"]===$pv_sslport) ? "https://" : "http://") : (($_SERVER["SERVER_PORT"]===$pv_sslport) ? "https://" : "http://");
$pv_URIprotocol
ahora es correcto y está listo para ser utilizado; example $site=$pv_URIprotocol.$_SERVER["SERVER_NAME"]
. Naturalmente, la cadena también podría reemplazarse por TRUE y FALSE. PV significa Variable PortalPress ya que es una copia y pega directo que siempre funcionará. Esta pieza se puede utilizar en un guión de producción.
Mi solución (debido a que las condiciones estándar [$ _SERVER [''HTTPS''] == ''on''] no funcionan en servidores detrás de un equilibrador de carga) es:
$isSecure = false;
if (isset($_SERVER[''HTTPS'']) && $_SERVER[''HTTPS''] == ''on'') {
$isSecure = true;
}
elseif (!empty($_SERVER[''HTTP_X_FORWARDED_PROTO'']) && $_SERVER[''HTTP_X_FORWARDED_PROTO''] == ''https'' || !empty($_SERVER[''HTTP_X_FORWARDED_SSL'']) && $_SERVER[''HTTP_X_FORWARDED_SSL''] == ''on'') {
$isSecure = true;
}
$REQUEST_PROTOCOL = $isSecure ? ''https'' : ''http'';
HTTP_X_FORWARDED_PROTO: un estándar de facto para identificar el protocolo de origen de una solicitud HTTP, ya que un proxy inverso (equilibrador de carga) puede comunicarse con un servidor web utilizando HTTP incluso si la solicitud al proxy inverso es HTTPS http://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Common_non-standard_request_headers
No creo que agregar un puerto sea una buena idea, especialmente cuando tienes muchos servidores con diferentes compilaciones. eso solo agrega una cosa más para recordar cambiar. mirando el documento, creo que la última línea de kaisers es bastante buena, así que:
if(!empty($_SERVER["HTTPS"]))
if($_SERVER["HTTPS"]!=="off")
return 1; //https
else
return 0; //http
else
return 0; //http
parece lo suficientemente perfecto.
Puede marcar $_SERVER[''SERVER_PORT'']
ya que SSL normalmente se ejecuta en el puerto 443, pero esto no es infalible.
Según la publicación de hobodave: "Establezca un valor no vacío si el script se consultó a través del protocolo HTTPS".
if (!empty($_SERVER[''HTTPS'']))
{
$secure_connection = true;
}
Si está usando Apache, siempre puede contar con
$_SERVER["REQUEST_SCHEME"]
para verificar el esquema de la URL solicitada. Pero, como se menciona en otras respuestas, es prudente verificar otros parámetros antes de suponer que SSL realmente se está utilizando.
Si está utilizando el equilibrador de carga de Incapsula, necesitará usar un IRule para generar un encabezado personalizado para su servidor. Creé un encabezado HTTP_X_FORWARDED_PROTO que es igual a "http" si el puerto está configurado a 80 y "https" si es igual a 443.
Si utiliza nginx como sistema de equilibrio de carga, compruebe $ _SERVER [''HTTP_HTTPS''] == 1 otras comprobaciones serán erróneas para ssl.
También considero que estos parámetros son aceptables y es probable que no tengan falsos positivos cuando cambio servidores web.
- $ _SERVER [''HTTPS_KEYSIZE'']
- $ _SERVER [''HTTPS_SECRETKEYSIZE'']
- $ _SERVER [''HTTPS_SERVER_ISSUER'']
$ _SERVER [''HTTPS_SERVER_SUBJECT'']
if($_SERVER[''HTTPS_KEYSIZE''] != NULL){/*do foobar*/}
Tengo que dar un paso más y determinar si el sitio al que me estoy conectando es compatible con SSL (un proyecto le pide al usuario su URL y debemos verificar que haya instalado nuestro paquete de API en un sitio http o https).
Aquí está la función que uso, básicamente, solo llame a la URL a través de cURL para ver si https funciona.
function hasSSL($url)
{
// take the URL down to the domain name
$domain = parse_url($url, PHP_URL_HOST);
$ch = curl_init(''https://'' . $domain);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, ''HEAD''); //its a HEAD
curl_setopt($ch, CURLOPT_NOBODY, true); // no body
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // in case of redirects
curl_setopt($ch, CURLOPT_VERBOSE, 0); //turn on if debugging
curl_setopt($ch, CURLOPT_HEADER, 1); //head only wanted
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); // we dont want to wait forever
curl_exec($ch);
$header = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($header === 200) {
return true;
}
return false;
}
Esta es la manera más confiable que he encontrado para no solo saber SI está usando https (como pregunta la pregunta), pero si PODRÍA (o incluso DEBERÍA) usar https.
NOTA: es posible (aunque no muy probable ...) que un sitio pueda tener diferentes páginas http y https (por lo tanto, si le dicen que use http, tal vez no necesite cambiar ...) La gran mayoría de los sitios son los mismos, y probablemente deberían redireccionarse ellos mismos, pero este control adicional tiene su uso (sin duda, como dije, en el proyecto donde el usuario ingresa su información de sitio y desea asegurarse desde el lado del servidor)
solo por interés, Chrome Canary en este momento envía
HTTPS : 1
al servidor, y dependiendo de cómo esté configurado el servidor, puede significar que recibirá lo siguiente
HTTPS : 1, on
Esto rompió nuestra aplicación porque estábamos probando si estaba encendido, lo que obviamente no es así. Por el momento, solo el canario de cromo parece hacer esto, pero vale la pena señalar que las cosas del canario generalmente aterrizan en cromo "normal" poco tiempo después.
$secure_connection = ((!empty($_SERVER[''HTTPS'']) && $_SERVER[''HTTPS''] != ''off'') || (!empty($_SERVER[''HTTP_HTTPS'']) && $_SERVER[''HTTP_HTTPS''] != ''off'') || $_SERVER[''REQUEST_SCHEME''] == ''https'' || $_SERVER[''SERVER_PORT''] == 443) ? true : false;
El código está comprobando todo lo posible y funciona también en el servidor web IIS. Chrome desde v44 no establece el encabezado HTTP: 1 por lo que es correcto verificar HTTP_HTTPS. Si este código no coincide con https, significa que su servidor web o servidor proxy está mal configurado. Apache por sí mismo establece el indicador HTTPS correctamente, pero puede haber un problema al usar el proxy (por ejemplo, nginx). Debe establecer un encabezado en el host virtual nginx https
proxy_set_header X-HTTPS 1;
y utilice algún módulo Apache para establecer la bandera HTTPS correctamente buscando X-HTTPS desde el proxy. Busque mod_fakessl, mod_rpaf, etc.