Introducción a AMFPHP

FlashAMFPHP es una implementación en PHP, gratuita y de código abierto del AMF (Action Message Format), el cual es un formato binario basado en SOAP. AMF permite la serialización binaria de objetos y tipos nativos de ActionScript 2 y ActionScript 3 para ser enviados a servicios del lado del servidor. AMFPHP permite que aplicaciones realizadas en Flash, Flex y AIR puedan comunicarse directamente con objetos de clases de PHP.

Prácticamente, la forma en la que funciona se resume en que podemos crear clases en PHP, acceder a los métodos de esas clases por medio de Flash, Flex o AIR y obtener los datos retornados por esos métodos. Por ejemplo, podemos crear una clase para conectarnos a una base de datos en MySQL. Esta clase podría contener un método para insertar datos a la base, otro método para generar consultas y obtener en nuestra aplicación de Flash, Flex o AIR los registros regresados por la consulta.

En esta entrada veremos cómo está formado el AMFPHP y cómo acceder a él desde Flash CS3. Para una mejor explicación de cómo acceder a AMFPHP haremos una sencilla clase en PHP la cual no accederá a ninguna base de datos (eso lo dejaremos para nuestro próximo tutorial).

Tutorial

1. Baja el archivo amfphp-1.9.beta.20080120.zip de aquí. El amfphp-1.9 lo podemos usar con ActionScript 3 (Flash CS3, Flex y AIR), mientras que la versión anterior puede ser usada con ActionScript 2.

2. Descomprímelo y ponlo en algún directorio de tu servidor Web, en tu directorio htdocs o www en tu localhost. Si lo deseas, puedes renombrar la carpeta y ponerle AMFPHP1.9.

La estructura del directorio quedaría de la siguiente manera (en mi caso, la carpeta AMFPHP1.9 la puse en la carpeta raíz de mi servidor):

–> root ó carpeta raíz
–>AMFPHP1.9 (D)
–> browser (D)
–> core (D)
–> services (D)
–> gateway.php
–> globals.php
–> json.php
–> phpinfo
–> xmlrpc

Donde (D) indica que se trata de un directorio. Observa la carpeta browser, si accediéramos a él desde el navegador observaremos una aplicación creada en Flex donde nos muestra la lista de servicios que tenemos en AMFPHP, como se muestra en la siguiente liga. Si es la primera vez que accedes al browser, aparecerá la siguiente ventana de configuración:

Imagen 1: Ventana de Configuración de AMFPHP

En esta ventana de configuración deberás asegurarte que la dirección del Gateway es correcta. Después de hacer click en el botón Save te aparecerá la lista de servicios. Por default y cuando todavía no hemos creado ningún servicio nuevo, solamente aparecerá el servicio DiscoveryService. Importante: Cuando tenemos servicios que deben acceder a una base de datos o tratan información importante o crítica, lo mejor será no poner el directorio browser en el servidor. Continuando con nuestra estructura de directorios, como podrás imaginar, todos nuestros servicios (clases en PHP) deberán ir en el directorio services.

3. Vamos a crear una sencilla clase de PHP, la cual simulará las operaciones básicas de una calculadora. Sus métodos serán sumar, restar, multiplicar y dividir. Cada método recibirá como parámetro los dos números sobre los cuales hay que hacer la operación. Nota: Este tutorial es solamente para explicar cómo funciona AMFPHP y cómo podemos acceder a él desde Flash. Es por eso que nuestra clase de ejemplo es muy sencilla y muchos de ustedes dirán que no se requiere de PHP para sumar, restar, multiplicar y dividir dos números =0).
En PHP, al igual que en Flash, el nombre del archivo de una clase deberá tener el mismo nombre de la clase; por lo tanto, crea un nuevo archivo PHP, nómbralo Calculadora.php y guárdalo dentro del directorio services de nuestra carpeta AMFPHP19. Coloca el siguiente código dentro de Calculadora.php:

<?php

class Calculadora
{
	/**
	 * Suma dos números pasados por parámetro
	 * @returns Regresa un valor numérico
	 */
	function sumar($numeroA, $numeroB)
	{
		return ($numeroA + $numeroB);
	}	

	/**
	 * Resta dos números pasados por parámetro
	 * @returns Regresa un valor numérico
	 */
	function restar($numeroA, $numeroB)
	{
		return ($numeroA - $numeroB);
	}

	/**
	 * Multiplica dos números pasados por parámetro
	 * @returns Regresa un valor numérico
	 */
	function multiplicar($numeroA, $numeroB)
	{
		return ($numeroA * $numeroB);
	}

	/**
	 * Divide dos números pasados por parámetro
	 * @returns Regresa un valor numérico
	 */
	function dividir($numeroA, $numeroB)
	{
		return ($numeroA / $numeroB);
	}
}

?>

Observa los comentarios antes de cada función; estos comentarios nos dan una descripción de qué es lo que hace cada método y además le estamos indicando qué es lo que nos regresa cada método (@returns). Si bien estos comentarios no son obligatorios, nos ayudarán a recordar en el momento en que queramos modificar el archivo. Además, dentro de la lista de servicios en el browser, cuando seleccionamos alguno de estos métodos se nos mostrará esta descripción (Como prueba, ingresa al navegador, de la lista de la izquierda selecciona la clase Calculadora y posteriormente selecciona de la ventana de la derecha el método dividir. Observarás que antes de los campos de texto para ingresar los números aparece la descripción del método). Ahora ingresa un número dentro del campo de texto $numeroA e ingresa otro número dentro del campo $numeroB, haz click en el botón Call y observa cómo en el área de resultados (Results) se muestra el resultado regresado por el método dividir de nuestra clase Calculadora en PHP.

4. Dentro de nuestra clase podemos utilizar métodos privados, los cuales no podrán ser utilizados desde el navegador de servicios (browser) ni desde nuestras aplicaciones en Flash, Flex o AIR. Esto es útil cuando dichos métodos realizan operaciones importantes o críticas y que requieran de mayor seguridad. Para establecer que un método es privado, bastará con agregarle un guión bajo (_) antes del nombre. Para hacer la prueba, agrega el siguiente código a la clase Calculadora.php (Insértalo antes de la última llave (}) y del tag de cierre de PHP (?>):

	 /**
	 * Este método es privado y no aparecerá en el browser de servicios
	 * @returns Regresa la fecha y tiempo del servidor
	 */
	function _esteMetodoEsPrivado() {
		$fecha_hoy = date("d/m/Y") . ' ' . date("H:i:s");
		return $fecha_hoy;
	}

Observa cómo en el código anterior el nombre de la función empieza con guión bajo _, eso quiere decir que se trata de un método privado. El código de este método privado lo que hace es regresarnos la fecha y el tiempo del servidor (por medio del método date).

Desde nuestra clase de PHP podemos acceder a ese método privado por medio de otro método. Para acceder a este método es necesario utilizar la palabra clave $this. A continuación te muestro cómo:

	 /**
	 * Este método es público y está accediendo a nuestro método privado
	 * @returns Regresa la fecha y tiempo del servidor
	 */
	function obtenFechaServidor() {
		$fecha_hoy = $this->_esteMetodoEsPrivado();
		return $fecha_hoy;
	}

El método obtenFechaServidor hace un llamado a la función esteMetodoEsPrivado y almacena en la variable $fecha_hoy el valor regresado por el método privado. Este valor es regresado por el método obtenFechaServidor.

Ingresa a nuestro navegador de servicios, selecciona la clase Calculadora y observa cómo el método esteMetodoEsPrivado no aparece dentro de los métodos de esta clase. Ahora haz click en el botón obtenFechaServidor y posteriormente en el botón Call. En el área de resultados (Results) se mostrará la fecha y hora del servidor.

Antes de pasar a la interfaz y al código ActionScript, te dejo el código completo del archivo Calculadora.php

<?php

class Calculadora
{
	/**
	 * Suma dos números pasados por parámetro
	 * @returns Regresa un valor numérico
	 */
	function sumar($numeroA, $numeroB)
	{
		return ($numeroA + $numeroB);
	}	

	/**
	 * Resta dos números pasados por parámetro
	 * @returns Regresa un valor numérico
	 */
	function restar($numeroA, $numeroB)
	{
		return ($numeroA - $numeroB);
	}

	/**
	 * Multiplica dos números pasados por parámetro
	 * @returns Regresa un valor numérico
	 */
	function multiplicar($numeroA, $numeroB)
	{
		return ($numeroA * $numeroB);
	}

	/**
	 * Divide dos números pasados por parámetro
	 * @returns Regresa un valor numérico
	 */
	function dividir($numeroA, $numeroB)
	{
		return ($numeroA / $numeroB);
	}

	/**
	 * Este método es privado y no aparecerá en el browser de servicios
	 * @returns Regresa la fecha y tiempo del servidor
	 */
	function _esteMetodoEsPrivado() {
		$fecha_hoy = date("d/m/Y") . ' ' . date("H:i:s");
		return $fecha_hoy;
	}

	/**
	 * Este método es público y está accediendo a nuestro método privado
	 * @returns Regresa la fecha y tiempo del servidor
	 */
	function obtenFechaServidor() {
		$fecha_hoy = $this->_esteMetodoEsPrivado();
		return $fecha_hoy;
	}
}

?>

5. Crea un nuevo documento de Flash en Flash CS3 ActionScript 3.0. Cambia las dimensiones del área de trabajo por 300px de ancho y 190px de alto. Renombra la única capa que existe y ponle de nombre Forma. Agrega 3 textos, 3 TextInput(s) y 4 botones de tal forma que tu forma quede similar a la de la imagen:

Imagen 2: Forma de nuestra aplicación

El nombre de instancia de cada uno de los TextInput(s) es (de arriba a abajo):

  • numeroA_txt
  • numeroB_txt
  • resultado_txt

El nombre de instancia de cada uno de los botones es (de arriba a abajo):

  • mas_btn
  • menos_btn
  • por_btn
  • entre_btn

6. Agrega otra capa y ponle de nombre Acciones. Agrega el siguiente código a dicha capa:

/* Las siguientes librerías son necesarias para hacer las llamadas y conexión a AMFPHP */
import flash.net.NetConnection;
import flash.net.Responder;

/* Dentro de la variable gateway especificamos la URL completa de donde se encuentra nuestro archivo gateway.php. Si estás trabajando en local, es posible que tu URL sea similar a  http://localhost/AMFPHP1.9/gateway.php */
var gateway:String = "http://localhost/AMFPHP1.9/gateway.php";
/* Creamos una variable de tipo NetConnection para poder establecer la conexión. Este objeto funcionará como enlace entre el cliente y el servidor */
var conexion:NetConnection = new NetConnection;
/* Establecemos una conexión bidireccional entre el Flash Player y el servidor */
conexion.connect(gateway);
/* Este objeto de clase Responder se encargará de administrar los valores que son regresados por el servidor, ya sea si la operación fue todo un éxito o si hubo un error */
var responder:Responder;
/* Deshabilitamos el campo de texto donde se mostrará el resultado para que sea sólo de lectura */
resultado_txt.enabled = false;

Revisa con atención el código anterior y los comentarios que están insertados en él. Hasta ahora solamente hemos importado las librerías que necesitamos, hemos declarado e instanciado las variables que usaremos a lo largo del programa.

Coloca el siguiente código debajo del anterior. Aquí estamos declarando cuatro métodos que serán llamados dependiendo de si el usuario hizo click en el botón de mas, menos, por o entre. Observa bien que el código de cada uno de estos métodos sólo cambia en la llamada de los métodos de la clase (la última línea de cada método, antes de }), es por eso que sólo comentaré la primera función (suma).

function suma(evento:MouseEvent) :void {
	/* Obtenemos el valor ingresado en cada uno de los campos de texto  */
	var numeroA:Number = Number(numeroA_txt.text);
	var numeroB:Number = Number(numeroB_txt.text);

	/* Le especificamos a la variable responder qué métodos debe llamar en caso de éxito (método respuesta) o en caso de error (método error)  */
	responder = new Responder(respuesta, error);			

	/* Invocamos, por medio del método call, al método sumar que se encuentra en la clase Calculadora (Calculadora.sumar). El segundo parámetro del método call es nuestro objeto de la clase Responder (el que se encargará de gestionar los valores obtenidos de dicha llamada. Por último, le pasamos como cuarto y quinto parámetro los dos números que deberá recibir la función sumar. */
	conexion.call("Calculadora.sumar", responder, numeroA, numeroB);
}

function resta(evento:MouseEvent) :void {
	var numeroA:Number = Number(numeroA_txt.text);
	var numeroB:Number = Number(numeroB_txt.text);

	operacion_mc.gotoAndStop("menos");
	responder = new Responder(respuesta, error);			

	conexion.call("Calculadora.restar", responder, numeroA, numeroB);
}

function multiplicacion(evento:MouseEvent) :void {
	var numeroA:Number = Number(numeroA_txt.text);
	var numeroB:Number = Number(numeroB_txt.text);

	operacion_mc.gotoAndStop("por");
	responder = new Responder(respuesta, error);			

	conexion.call("Calculadora.multiplicar", responder, numeroA, numeroB);
}

function division(evento:MouseEvent) :void {
	var numeroA:Number = Number(numeroA_txt.text);
	var numeroB:Number = Number(numeroB_txt.text);

	operacion_mc.gotoAndStop("entre");
	responder = new Responder(respuesta, error);			

	conexion.call("Calculadora.dividir", responder, numeroA, numeroB);
}

Después del código anterior solamente nos faltan los métodos respuesta y error, además de las acciones de cada uno de nuestros botones:

/* En caso de éxito tras ejecutar el método call, esta función es llamada pasándole como parámetro un objeto con el resultado regresado. Este resultado lo mostraremos dentro del TextInput resultado_txt. */
function respuesta(resultado:Object):void {
	resultado_txt.text = String(resultado);
}

/* En caso de error tras ejecutar el método call, esta función es llamada pasándole como parámetro un objeto con el error generado. Este error lo desplegaremos dentro de un trace. */
function error(error:Object):void {
	trace("Error: " + error.description);
}

/* Establecemos las acciones de nuestros botones */
mas_btn.addEventListener(MouseEvent.CLICK, suma);
menos_btn.addEventListener(MouseEvent.CLICK, resta);
por_btn.addEventListener(MouseEvent.CLICK, multiplicacion);
entre_btn.addEventListener(MouseEvent.CLICK, division);

A continuación puedes ver el SWF funcionando. A este archivo le añadí un campo de texto dinámico en el lado inferior derecho en el cual muestro el resultado de hacer una llamada al método obtenFechaServidor de nuestra clase Calculadora. No olvides bajar los archivos de este tutorial que se encuentran al final de esta entrada.


Este archivo requiere Flash Player 8
Descargar Archivo
Category: Flash, PHP  Tags: , ,
You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.
33 Responses
  1. berenice dice:

    Oye, disculpa porque no veo el resultado?

  2. Francisco Jiménez dice:

    A ver si alguien me puede ayudar, todo funciona bien mientras tengas los archivos en el mismo dominio donde esta instalado el AMFPHP, pero si pones los archivos en otro dominio, esto no funciona, nadie sabe por que? como se puede solucionar esto. saludos y gracias

  3. jose vicente dice:

    ¿Porque habéis dejado de escribir más artículos en este formidable blog? es de lo mejor que he visto. Por favor crear mas artículos, ejemplos y proyectos. Muchas gracias.

  4. Francis dice:

    Hola pude resolver el problema siguiendo lo que dice lucy , no me funciono al comienzo porque cometi la torpeza de no ——-reiniciar el apache pero ya esta Gracias lucy

    .—————————————–

    Bueno, despues de volverme loca buscando he encontrado el problema. El error que me imprimia en el panel de salida solo aparecia cuando estaba controlando la pelicula desde Flash IDE, una vez publicado el swf este no tenia ningun error aparente.
    Solucion: en gateway.php comentar las siguientes lineas :
    //Disable profiling, remote tracing, and service browser
    $gateway->disableDebug();
    // Keep the Flash/Flex IDE player from connecting to the gateway. Used for security to stop remote connections.
    $gateway->disableStandalonePlayer();
    Espero que a alguien le sirva de ayuda

  5. Francis dice:

    Hola acabo de instalar el amfphp copie la carpeta en la raiz de mi servidor
    pero me arroja un error cuando abro la ruta
    http://localhost/amfphp/browser

    Me muestra una ventana con el codigo de error

    (mx.rpc::Fault)#0
    errorID = 0
    faultCode = “Client.Error.MessageSend”
    faultDetail = “Channel.Connect.Failed error NetConnection.Call.BadVersion: ”
    faultString = “Send failed”
    message = “faultCode:Client.Error.MessageSend faultString:’Send failed’ faultDetail:’Channel.Connect.Failed error NetConnection.Call.BadVersion: ‘”
    name = “Error”
    rootCause = (Object)#1
    code = “NetConnection.Call.BadVersion”
    description = “”
    details = “”
    level = “error”

    Puedes tu ayudarme porfavor me estoy volviendo loco no se que hacer

    Ya intente con comentar las lineas que indica lucy pero aun asi no me funciona ayuda porfavor quien sea

    Gracias

  6. mike dice:

    hola. Estoy usando (wamp 2.0, amfphp 1.9 y as3). Cuando compilo mi archivo fla me tirar el error “Error #2044: NetStatusEvent ” buscando en goole encontre e hice varias de las recomendaciones como ser : comentar en gateway.php -$gateway->disableStandalonePlayer();
    -$gateway->disableDebug();
    -setear a false define(“PRODUCTION_SERVER”, false);
    para que puede probar mi webservice en modo standalone, el tema es que sigue sin fucionarme incluso cuando ejecuto el swf solamante [ej->http://localhost/misitioweb/usuarios.swf] en mi browser (firefox) esquina izquiera inferior aparece el texto “esperando localhost” lo unico que hace mi swf es un select de (nombre y apellido) en una BD existente obviamente pero nada sucede, probe mi clase php desde el mismo amfphp y no tiene errores es mas me trae el nombre y apellido [http://localhost/amfphp1.9/browser/]. Pero cuando lo llamo al servicio desde el swf NADA SUCEDE queda esperando al localhost????

    NOTA IMPORTANTE viendo el log de errores del apache encontre esto->
    “PHP Fatal error: Uncaught exception ‘VerboseException’ with message ‘Web services are not supported in this release’ in C:\\wamp\\www\\amfphp 1.9\\core\\amf\\app\\Actions.php:127\nStack trace:\….etc”

    esto me parece que incluso ya no es problemas del gateway.php, standalone, nada….AYUDA!!!

  7. Jorge dice:

    Hola Carla.

    Antes que nada felicidades por el tutorial está muy bien explicado y muy sencillo de seguir.

    Por otro lado he probado todo en mi máquina local y funciona a la perfección pero al momento de instalar AMFPHP 1.9 en mi sitio de hospedaje, el browser me pone el siguiente error:

    ———————————————————
    (mx.rpc::Fault)#0
    errorID = 0
    faultCode = “Client.Error.MessageSend”
    faultDetail = “Channel.Connect.Failed error NetConnection.Call.Failed: HTTP: Status 406″
    faultString = “Send failed”
    message = “faultCode:Client.Error.MessageSend faultString:’Send failed’ faultDetail:’Channel.Connect.Failed error NetConnection.Call.Failed: HTTP: Status 406′”
    name = “Error”
    rootCause = (Object)#1
    code = “NetConnection.Call.Failed”
    description = “HTTP: Status 406″
    details = “http://www.midominio.com.mx/amfphp/gateway.php”
    level = “error”
    ——————————————————

    Alguien sabe como solucionarlo o a que se debe??????

  8. Abraham dice:

    Muchas gracias Lucy!! Ya me estaba volviendo loco XD

  9. Hola Lucy,

    Gracias por compartir tu solución =0)

    Saludos.

  10. Lucy dice:

    Bueno, despues de volverme loca buscando he encontrado el problema. El error que me imprimia en el panel de salida solo aparecia cuando estaba controlando la pelicula desde Flash IDE, una vez publicado el swf este no tenia ningun error aparente.
    Solucion: en gateway.php comentar las siguientes lineas :

    //Disable profiling, remote tracing, and service browser
    $gateway->disableDebug();
    // Keep the Flash/Flex IDE player from connecting to the gateway. Used for security to stop remote connections.
    $gateway->disableStandalonePlayer();

    Espero que a alguien le sirva de ayuda.

  11. Lucy dice:

    Hola, he seguido el tutorial paso a paso, y tambien he probado los archivos bajados. Haga lo que haga para utilizar amfphp me sale este error :

    Error #2044: NetStatusEvent no controlado: level=error, code=NetConnection.Call.BadVersion

    No entiendo porque, he buscado y rebuscado en google pero no doy con la solución y peor todavia no doy con la fuente del error. Alguien sabe porque sale este error?
    Gracias

  12. Jesus Pablo dice:

    Hola.
    Me parecio muy util e intersante el tutorial.
    Pero tengo una pregunta, actualmente me encuentro desarrollando una aplicación en adobe air, y al menos a mi cuando aprendi a usar flex, me enseñaron que las aplicaciones de escritorio (air) se guardan en la unidad C:\ [por seguridad] de modo que cuando quiero ejecutar mis registros usando amfphp, me marca error.

    Quiza sea porque amfphp debe estar dentro de la carpeta del appserv, pero esa es justamente mi pregunta.
    ¿Se conecta de la misma manera adobe air y amfphp que si conectase flex y amfphp?
    y la segunda
    ¿En que carpeta debe estar el amfphp?

    Gracias.

  13. [...] Importante: Dentro de nuestra clase podemos utilizar métodos privados, los cuales no podrán ser utilizados desde el navegador de servicios (browser) ni desde nuestras aplicaciones en Flash, Flex o AIR. Esto permite crear funciones que realicen operaciones importantes o que requieran mayor seguridad como lo muestra Carla en su Post Original. [...]

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>