entre Desarrolladores

Recibe ayuda de expertos

Registrate y pregunta

Es gratis y fácil

Recibe respuestas

Respuestas, votos y comentarios

Vota y selecciona respuestas

Recibe puntos, vota y da la solución

Pregunta

1voto

¿Es posible transmitir un video de esta forma con php?

Un saludo a todos.

Se me ha encargado "intentar" proteger un video para que no pueda ser descargado desde el servidor. Aunque todos sabemos que, "si se puede ver, se puede descargar", el objetivo es que al menos sea lo más difícil posible para un usuario intermedio.

Entre mis ideas está usar un token de verificación para que no exista una url fija del video, algo como:

/video.php?token=xxxx

Siendo "xxxx" un token generado al momento de darle play, y que solo tendrá validez durante cierto tiempo antes de que expire. Pero entonces el problema que tengo es cómo puedo hacer que " /video.php?token=xxxx" sea una url que tenga un flujo de datos que sea aceptado por las etiquetas <video></video> o por los reproductores de terceros que se pueden encontrar por internet.

En otras palabras, que "/video.php?token=xxxx" sea aceptado por los reproductores de video y que sea equivalente a poner "archivo.mp4" como fuente de datos, por ejemplo.

¿Alguien conoce la forma correcta de abordar este problema? ¿o se les ocurre una forma mejor de poder proteger el video de ser descargado con facilidad de las muchas extensiones que existen para tal tarea?

Gracias de antemano.

1 Respuesta

1voto

Leonardo-Tadei Puntos227320

Hola,

podrías hacer algo como:

  $name = "archivo.mp4";
  ob_end_clean();
  $path = "protected/".$name;
  if (!is_file($path) or connection_status()!=0) return(FALSE);
  header("Cache-Control: no-store, no-cache, must-revalidate");
  header("Cache-Control: post-check=0, pre-check=0", false);
  header("Pragma: no-cache");
  header("Expires: ".gmdate("D, d M Y H:i:s", mktime(date("H")+2, date("i"), date("s"), date("m"), date("d"), date("Y")))." GMT");
  header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
  header("Content-Type: application/octet-stream");
  header("Content-Length: ".(string)(filesize($path)));
  header("Content-Transfer-Encoding: binary\n");
  if ($file = fopen($path, 'rb')) {
    while(!feof($file) and (connection_status()==0)) {
      print(fread($file, 1024*8));
      flush();
    }
    fclose($file);
  }
  return((connection_status()==0) and !connection_aborted());

Tal vez debas ajustar el tipo MIME a el tipo de vide correspondiente, pero si vas a usar un reproductor embebido, no haría falta.

Si el directorio protegido está más atrás de la ruta del directorio público del hosting, no será accesible invocándolo directamente desde el navegador, así que te podés ahorrar el parámetro identificador del archivo real.

Si no tenés ningún directorio usable por detrás del DOCUMENT_ROOT, podrías crar una regla htaccess para que no se pueda acceder: el script PHP sí accederá porque él usa el sistema de archivos directamente y no URLs que se interceptan por el servidor web.

A esto tenés que agregarle alguna restricción para que si el archivo PHP responda solo si es llamado desde el script que lo va a invocar. Eso se podría escribir:

// Verifica que el llamador sea únicamente $referer
$refererArray = explode('?', basename($_SERVER['HTTP_REFERER']));
$referer = $refererArray[0];
if($referer != 'tu_script_que_llama_al_video.php')
{ die("Llamada incorrecta (X)"); }

De esta forma cualquier llamada desde el navegador o desde otro archivo no devuelve el video. Podrías relajar más la restricción y permitir cualqueir llamada desde tu propio servidor usando otras variables de entorno.

Saludos!

0voto

HoberMallow comentado

Muchas gracias Leonardo, como siempre una respuesta eficaz. La solución que planteas funciona perfectamente para que el flujo de datos venga del archivo .php y no del .mp4 y también he creado las reglas con htaccess para negar el acceso a este último.
He aplicado la restricción en el archivo php para únicamente pueda se ejecute cuando tiene como referer el reproductor, y en efecto, ahora ya no puede ser llamado directamente desde el navegador.

El problema con el que estoy dándome es que la extensión para Chrome FVD Downloader detecta como contenido multimedia el archivo .php a la hora de darle play y aún se puede descargar. Entonces lo único que hay que hacer es cambiar la extensión php por mp4 y el video ya queda listo para ser visto localmente.

¿Se te ocurre algún método de evitar esto?

0voto

Leonardo-Tadei comentado

Me alegro que te haya servido!

Respecto a las extensiones para descarga de videos (yo uso Download Helper en Firefox) tal vez puedas engañarlos emitiendo un tipo MIME incorrecto, como por ejemplo un ZIP o un formato raro: si el reproductor de video que usás no está verificando el tipo MIME para saber qué reproducir, es posible que despistes a algunos plugins, pero dependerá en gran medida de cómo está escrito y de qué es lo que revisa para ofrecer la descarga.

Contame lo que pruebes a este respecto, así aperndo sobre esos detalles!

0voto

HoberMallow comentado

Hola Leonardo, probé cambiar el MIME Type por el de un zip o un formato extraño y lo que pasa es que el FVD descarga el video como un ZIP o el tipo de formato que haya puesto en el MIME, entonces siempre solo basta cambiar la extensión y ya esta listo para ver. Muy molesto.
Al final la única forma que encontré para inutilizar la extensión fue haciendo el link al archivo de video .php desechable por medio de un token como había planteado originalmente. En la página del script creo un token para un solo uso y lo mando a una base de datos, luego en la página video.php valido el token y luego lo borro de la BD. Así el reproductor logra transmitir el video pero cuando la extensión hace un nuevo request al archivo .php el token ya no es valido y solo logra descargar un archivo de 0 bytes.
Con esto ya logro evitar las dos extensiones, FVD Dowloader y Download Helper, el problema con el que me he topado es que en efecto el reproductor solo logra transmitir el video una sola vez, al darle replay ya no funciona porque el token ya no existe.

Y otro problema algo extraño es con la restricción para que el .php no pueda ser llamado directamente. Al parecer la restricción trabaja bien en Chrome y Firefox, pero no así en Opera y el resto de navegadores de escritorio y móviles.

Entonces se me ocurrieron dos formas de intentar solucionar el problema. La primera fue hacer que el .php solo responda a las llamadas desde el servidor de la siguiente forma:

if ($_SERVER['SERVER_ADDR'] == $_SERVER['REMOTE_ADDR']) {
   ... El código para transmitir el video.
}

Pensando que ya que es el archivo principal del script del reproductor el que iba a llamar a video.php, las dos ips iba a coincidir, pero al parecer no fue así y siempre marca la ip de mi equipo como referer, entonces la condición no se valida.
Entonces pensé en relajar más la condición y al menos evitar que el archivo php no pudiera ser llamado de forma directa con:

$referer = $_SERVER['HTTP_REFERER'];
if(!is_null($referer)) {
  ...El código
}

Y de esta forma logro que funcione al menos en los navegadores de escritorio pero no en los navegadores móviles. La única forma en la que logro que se reproduzca en todos lados es eliminando la restricción por completo. ¿Alguna idea Leonardo? Gracias por adelanto.

PD: Creo que nunca mencione que estoy trabajando con el reproductor jwplayer.

0voto

Leonardo-Tadei comentado

Hola hobermallow,

gracias por compartir la solución referente a los programas de desarga y el token. Es cierto que esto implica que el video no podrá volver a verse, salvo claro que se recargue la página... tal vez puedas hacer que el botón para volver a reproducir recargue la página o el iframe en dónde está el video, como una forma de workarround.

Con este problema de no poder volver a reproducir: te funciona correctamente poner en pausa el video?

Respecto a lo que contás de las variables $_SERVER estás haciendo algo mal o interpretando mal su significado... son variables que completa el servidor y por tanto casi ninguna depende del navegador que usás! Tal vez valga la pena que crees otra pregunta sobre esta cuestión en particular, para no mezcalr los temas y para que otros se sumen, ya que en esta pregunta no creo que nadie participe sobre esta cuestión en particular.

Saludos!

1voto

HoberMallow comentado

Gracias por responder Leonardo, creo que tenés razón y es mejor abrir un nuevo hilo ya que el original ya fue resuelto.

Respecto a poner pausa, eso sí funciona sin problemas, lo único que no funciona con la solución de reproducir desde el php es el poder adelantar o retroceder el video. Aunque para efectos prácticos y para el uso que tendrá el reproductor no es algo muy importante. Aunque vale la pena mencionarlo.

Por favor, accede o regístrate para responder a esta pregunta.

Otras Preguntas y Respuestas


...

Bienvenido a entre Desarrolladores, donde puedes realizar preguntas y recibir respuestas de otros miembros de la comunidad.

Conecta