Cursos Asterisk en México

AGI en PHP desde el principio!!

Colapsar

Anuncio

Colapsar
No hay anuncio todavía.
X
 
  • Filtrar
  • Tiempo
  • Mostrar
Limpiar Todo
nuevos mensajes

  • AGI en PHP desde el principio!!

    Lo primero que hay que entender es qué es un AGI y qué se puede hacer con él.

    AGI (Asterisk Gateway Interface) permite programar funcionalidades en diferentes lenguajes PHP, Perl, Java, C, en fin, mediante una interfaz transparente al usuario haciendo modificaciones a bases de datos, consultando estados de variables, controlar el dIalplan, etc.. haciendo la llamada desde el archivo extensions.conf

    Hasta aquí todo claro..se pone bueno cuando intentamos crear un AGI en PHP puesto que no entendemos la estructura de uno y mucho menos encontramos para que sirve cada instrucción.

    Aquí veremos poco a poco cada sección y les pido un poco de paciencia porque en un solo mensaje no cabe todo.

    ESTRUCTURA DEL PROGRAMA

    #!/usr/bin/php --> Permite crear un scrip que será ejecutado por el programa que se encuentra en está ruta.

    <?php --> Etiqueta que indica la inclusión de código php. Sin está etiqueta es imposible códificar en el lenguaje PHP.

    $stdin = fopen("php://stdin","r"); --> Entradas que se tengan del canal o línea que se está utilizando en ese momento cuando se ejecutó el AGI.

    $stdout = fopen("php://stdout","w"); --> Salidas que se hagan hacia el canal o línea que se está utilizando en ese momento cuando se ejecutó el AGI. También sirve para ejecutar comandos del Dial Plan. Pero se creará na función para ello más adelante.

    $stdlog = fopen("/var/log/asterisk/my_agi.log","w"); --> Log de errores o novedades que serán guardado en el directorio y archivo especificados.

    Hasta ahora no hemos hecho sino definir las variables que contendran entradas y salidas. Pero como hacemos para capturar valores ?

    // Permite pasar los encabezados de entrada de las variables AGI dentro de un array y ser asignadas a variables posteriormente.

    while (!feof($stdin)) {
    $temp = fgets($stdin);
    $temp = str_replace("\n","",$temp);
    $s = explode(":",$temp);
    $agivar[$s[0]] = trim($s[1]);
    if (($temp == "") || ($temp == "\n")) {
    break;
    }
    }

    Este while toma entrada por entrada y las coloca en el array AGIVAR para consultarlas posteriormente o ser asignadas a otras variables como sigue el ejemplo:

    //Captura y define las variables
    $request = $agivar['agi_request'];
    $channel= $agivar['agi_channel'];
    $type= $agivar['agi_type'];
    $uniqueid= $agivar['agi_uniqueid'];
    $callerid= $agivar['agi_callerid'];
    $context= $agivar['agi_context'];
    $extension= $agivar['agi_extension'];
    $priority= $agivar['agi_priority'];
    $accountcode= $agivar['agi_accountcode'];
    /** OTRAS VARIABLES **/
    $calleridname= $agivar['agi_calleridname'];
    $callingpres= $agivar['agi_callingpres'];
    $callingani2= $agivar['agi_callingani2'];
    $callington = $agivar['agi_callington'];
    $callingtns= $agivar['agi_callingtns'];
    $dnid= $agivar['agi_dnid'];
    $rdnis= $agivar['agi_rdnis'];
    $enhanced= $agivar['agi_enhanced'];

    Como pueden observar estamos transfiriendo los valores capturados con el WHILE del array AGIVAR a otras variables. Tambien se pueden trabajar directamente desde el array pero personalmente no lo recomiendo por facilidad de manejo.

  • #2
    Gracias

    me parece fantastico....
    ya tengo algunas preguntas y sorry si son demasiado obvias

    literalmente esto seria


    while (!feof($stdin)) {
    aqui empieza el bucle... "!feof" es como el fin de archivo end of file...
    significa que la lectura se hara hasta que haya algo en el canal

    $temp = fgets($stdin);
    aqui se almacenan en $temp(meimagino es una variable) todo lo que haya en el canalen ese momento. si esto que digo es correcto, "todo" equivale a las variables que definiste mas abajo, me refiero a la lista...

    $request = $agivar['agi_request'];
    $channel= $agivar['agi_channel'];
    $type= $agivar['agi_type'];
    $uniqueid= $agivar['agi_uniqueid'];
    $callerid= $agivar['agi_callerid'];
    etc


    $temp = str_replace("\n","",$temp);
    $s = explode(":",$temp);
    esto ni idea para que, al parecer preparas el formato de las variables...

    $agivar[$s[0]] = trim($s[1]);
    aqui las traspasas ?

    if (($temp == "") || ($temp == "\n")) {
    condicion de termino... pero como funciona.

    break;


    Danilo
    gracias

    }
    }

    Comentario


    • #3
      Ok.

      El While siempre debe ir para capturar las variables y los valores que se quieren consultar.

      Miremos el WHILE con detenimiento:

      Código:
      while (!feof($stdin)) {
      aqui empieza el bucle... "!feof" es como el fin de archivo end of file...
      significa que la lectura se hara hasta que haya algo en el canal
      Efectivamente todas las variables que se generan como entrada del canal quedan en un buffer y se debe leer línea por línea hasta que no haya nada más. Hay que hacer el while del inicio hasta el final.

      Código:
      $temp = fgets($stdin);
      aqui se almacenan en $temp(meimagino es una variable) todo lo que haya en el canalen ese momento. si esto que digo es correcto, "todo" equivale a las variables que definiste mas abajo, me refiero a la lista...
      Se lee del buffer hasta ahora solo tenemos una cadena (línea por línea) y no la hemos pasado al array porque primero hay que depurarla.

      Código:
      $temp = str_replace("\n","",$temp);
      Esto es lenguaje PHP y se utiliza la funcion de reemplazar un caracter en una cadena. Estamos reemplazando el salto de línea por espacio vacio. Quiere decir estamos borrando donde aparezaca salto de línea en la línea que acabamos de leer.

      Código:
      $s = explode(":",$temp);
      Esta también es una función de PHP y permite ingresar en un array los valores que se encuentran en una cadena pero cada valor dentro de la cadena es separado del otro por un caracter especificico (en este caso ":"). Quiere decir que en $temp tenemos un string de valores separados por ":" y para manejarlos mas facilmente los pasamos al array $s separando los valores uno de otro (un valor es el nombre de la variable y el otro es el dato que contiene).

      Código:
      $agivar[$s[0]] = trim($s[1]);
      aqui las traspasas ?
      Si aqui se toman los valores del array $s que contiene en la posición 0 el nombre de la variable y en la posición 1 el valor de esa variable. Se genera en el array $agivar un elemento que se llamara como la variable y que contendrá su valor respectivo. La función trim elimina espacios en blanco.

      Código:
      if (($temp == "") || ($temp == "\n")) { break; }
      condicion de termino... pero como funciona.
      Esto garantiza que si en la última lectura antes de llegar al final del archivo se leyo vacio o salto de línea no permita procesar estos valores y se salga del ciclo.

      Seguimos poco a poco hasta que vayan entendiendo!

      Comentario


      • #4
        como seria la estructura de este buffer, es decir si le sacaramos una foto como seria ???... es que necesito aclarara algo ...
        seria una sola linea variable y dato todo junto...

        $temp = fgets($stdin);
        $temp=var1dato1var2dato2var3dato3...varndaton por ejemplo

        como quedaria despues de esto
        $temp = str_replace("\n","",$temp);

        y despues de esto
        $s = explode(":",$temp);


        esto $agivar[$s[0]] = trim($s[1]);
        generaria esto:

        $request = $agivar['agi_request'];
        $channel= $agivar['agi_channel'];
        $type= $agivar['agi_type'];
        $uniqueid= $agivar['agi_uniqueid'];
        $callerid= $agivar['agi_callerid'];
        $context= $agivar['agi_context'];
        $extension= $agivar['agi_extension'];
        $priority= $agivar['agi_priority'];
        $accountcode= $agivar['agi_accountcode'];



        SORRY SI PARECE QUE ESTUVIERA PREGUNTANDO LO MISMO, PERO SI LOGRO GRAFICAR ESTO ME RESULTARA MAS CLARO LO QUESIGUE.

        GRACIAS
        Danilo Reyes

        Comentario


        • #5
          Uy bastian_x..creo que nunca has programado, pero no te preocupes, vamos paso a paso para que vayas entendiendo.

          Con esta intrucción $stdin = fopen("php://stdin","r"); estamos metiendo todo lo que hay en la entrada del canal que estamos trabajando (que vendrían siendo las variables y sus valores). Hasta ahí todo claro!!

          al hacer esta instrucción $temp = fgets($stdin); que podría quedar en la variable $temp?
          Lo que posiblemente quedaría sería:
          $temp = '\n agi_channel: Zap/17-1 \n'

          Cómo quedaria despues de esto $temp = str_replace("\n","",$temp); . Esto daría algo como esto (para cada línea leida..ojo):
          $temp = ' agi_channel: Zap/17-1 '

          y despues de esto $s = explode(":",$temp);. Sería algo así:
          $s = [' agi_channel', ' Zap/17-1 ']
          o sea esto $s[0] = ' agi_channel' y $s[1] = ' Zap/17-1 '

          y esto $agivar[$s[0]] = trim($s[1]); qué generaria?
          Pues estamos llenando una array donde cada posición es el nombre de la variable y el sontenido de esa posición es su valor. Recuerda que la función TRIM elimina los espacios en blanco.
          $agivar['agi_channel'] = 'Zap/17-1'

          Estos pasos se hacen para cada línea leida del buffer (cuando digo buffer es lo que se está leyendo de $stdin asignada en un principio). Esto quiere decir que todas las variables quedarán en el array $agivar con su respectivo valor.

          Ya teniendo en el array $agivar todas las variables con sus valores pues sencillamente es asignarlas a otras variables, conectarse a la base de datos, etc..

          Si entendiste esto, podemos pasar al siguiente punto:

          Ok?

          --> EJECUTAR COMANDOS DEL DIAL PLAN DESDE EL AGI

          Se pueden ejecutar comandos del DIAL PLAN desde el AGI en PHP? ..la respuesta es SI. Fijate que esto sería una salida!! y por lo tanto podemos crear una función para ejecutar estos comandos.

          Comentario


          • #6
            Yap

            me quedo clarito....

            gracias por la paciencia...

            thank a lot

            continuemos maestro....

            tiene toda mi atencion...

            Comentario


            • #7
              Recuerda que asi se iniciaria el AGI, entonces despues de inciar el agi podemos definir unas constantes con nombre (sería como variables pero no se pueden cambiar).

              #!/usr/bin/php -q
              <?php
              //Definicion de Constantes con Nombre
              define('AST_STATE_DOWN', 0);
              define('AST_STATE_RESERVED', 1);
              define('AST_STATE_OFFHOOK', 2);
              define('AST_STATE_DIALING', 3);
              define('AST_STATE_RING', 4);
              define('AST_STATE_RINGING', 5);
              define('AST_STATE_UP', 6);
              define('AST_STATE_BUSY', 7);
              define('AST_STATE_DIALING_OFFHOOK', 8);
              define('AST_STATE_PRERING', 9);

              O sea, que cuando hagas referencia a alguno de estos nombres realmente estas comparando con el numero que se le definio. Pero es mejor manejarlo de esta manera porque podemos identificar que es lo que esta pasando cuando se devuelve una constante.

              Despues de esto, creamos entonces la funcion para ejecutar los comandos del dial plan.

              //Funcion para Ejecutar Comandos de ASTERISK
              function execute($command) {
              global $stdin, $stdout;
              fputs($stdout, $command . " \n");
              fflush($stdout);
              $data = fgets($stdin, 4096);
              if (preg_match("/^([0-9]{1,3}) (.*)/", $data, $matches)) {
              if (preg_match('/^result=([0-9a-zA-Z]*)( ?\((.*)\))?$/', $matches[2], $match)) {
              $arr['code'] = $matches[1];
              $arr['result'] = $match[1];
              switch($arr['result'])
              {
              case -1: $arr['data'] = trim("There is no channel that matches $channel"); break;
              case AST_STATE_DOWN: $arr['data'] = 'Channel is down and available'; break;
              case AST_STATE_RESERVED: $arr['data'] = 'Channel is down, but reserved'; break;
              case AST_STATE_OFFHOOK: $arr['data'] = 'Channel is off hook'; break;
              case AST_STATE_DIALING: $arr['data'] = 'Digits (or equivalent) have been dialed'; break;
              case AST_STATE_RING: $arr['data'] = 'Line is ringing'; break;
              case AST_STATE_RINGING: $arr['data'] = 'Remote end is ringing'; break;
              case AST_STATE_UP: $arr['data'] = 'Line is up'; break;
              case AST_STATE_BUSY: $arr['data'] = 'Line is busy'; break;
              case AST_STATE_DIALING_OFFHOOK: $arr['data'] = 'Digits (or equivalent) have been dialed while offhook'; break;
              case AST_STATE_PRERING: $arr['data'] = 'Channel has detected an incoming call and is waiting for ring'; break;
              default: $arr['data'] = "Unknown ({$arr['result']})"; break;
              }
              if (isset($match[3]) && $match[3])
              $arr['data'] = $match[3];
              return $arr;
              } else return 0;
              } else return -1;
              }

              Espero tus preguntas, compadre!

              Comentario


              • #8
                Esto no te va a gustar...


                <?php
                //Definicion de Constantes con Nombre ------> no questions

                Despues de esto, creamos entonces la funcion para ejecutar los comandos del dial plan.

                //Funcion para Ejecutar Comandos de ASTERISK
                function execute($command) { -----> una funcion con argumento $command
                global $stdin, $stdout; -----> defines como variables $stdin, $stdout
                fputs($stdout, $command . " \n"); -----> pones en $stdout lo q hay en $command ???
                que hay en command??

                fflush($stdout); -------> ni idea
                $data = fgets($stdin, 4096); -----> almacenas en $data=lo que hay en el canal
                me imagino 4096 es un anexo o un puerto


                de aqui------------>

                if (preg_match("/^([0-9]{1,3}) (.*)/", $data, $matches)) {
                if (preg_match('/^result=([0-9a-zA-Z]*)( ?\((.*)\))?$/', $matches[2], $match)) {
                $arr['code'] = $matches[1];
                $arr['result'] = $match[1];


                hasta aqui --------> limpiando para ver que hay en $data!!!!

                de aqui ----------------->
                switch($arr['result'])
                {
                case -1: $arr['data'] = trim("There is no channel that matches $channel"); break;
                case AST_STATE_DOWN: $arr['data'] = 'Channel is down and available'; break;
                case AST_STATE_RESERVED: $arr['data'] = 'Channel is down, but reserved'; break;
                case AST_STATE_OFFHOOK: $arr['data'] = 'Channel is off hook'; break;
                case AST_STATE_DIALING: $arr['data'] = 'Digits (or equivalent) have been dialed'; break;
                case AST_STATE_RING: $arr['data'] = 'Line is ringing'; break;
                case AST_STATE_RINGING: $arr['data'] = 'Remote end is ringing'; break;
                case AST_STATE_UP: $arr['data'] = 'Line is up'; break;
                case AST_STATE_BUSY: $arr['data'] = 'Line is busy'; break;
                case AST_STATE_DIALING_OFFHOOK: $arr['data'] = 'Digits (or equivalent) have been dialed while offhook'; break;
                case AST_STATE_PRERING: $arr['data'] = 'Channel has detected an incoming call and is waiting for ring'; break;
                default: $arr['data'] = "Unknown ({$arr['result']})"; break;
                }

                hasta aqui------------> identificas y clasificas el resultado de $data

                de aqui -------->

                if (isset($match[3]) && $match[3])
                $arr['data'] = $match[3];
                return $arr;
                } else return 0;
                } else return -1;
                }
                hasta aqui-----> ni idea


                Danilo

                Comentario


                • #9
                  QUE PASO PROFE ...?????

                  Comentario


                  • #10
                    Que pena brother,
                    Eh estado muy ocupado pero creo que pronto retomaremos esto.
                    Sin embargo, si quieres programar en PHP primero debes aprenderlo porque me haces preguntas que no tienen que ver con Asterisk o AGI, si no con funciones de PHP.

                    Saludos

                    Comentario


                    • #11
                      Concuerdo con Jorge: es necesario que aprendas un poco más de programación antes de seguir, porque veo tus dudas y son muy básicas, sin tener que ver con AGIs sino más bien con PHP.

                      De cualquier manera, te doy un poco de ayuda para que te quede más claro.

                      //Funcion para Ejecutar Comandos de ASTERISK
                      function execute($command) { -----> una funcion con argumento $command
                      global $stdin, $stdout; -----> defines como variables $stdin, $stdout
                      fputs($stdout, $command . " \n"); -----> pones en $stdout lo q hay en $command ???
                      que hay en command??
                      Primera, fputs no hace lo que tu crees. Fputs está escribiendo al output stream (en este caso, el CLI de Asterisk) el contenido de $command.
                      $command es el nombre de la variable que contiene los parámetros que se le pasaron a la función. Si yo invoco execute("VERBOSE Hola"), entonces $command seria igual a "VERBOSE Hola". Esto es básico en programación
                      fflush($stdout); -------> ni idea
                      $data = fgets($stdin, 4096); -----> almacenas en $data=lo que hay en el canal
                      me imagino 4096 es un anexo o un puerto
                      El fflush manda inmediatamente lo que se haya guardado en el buffer. Es como decir "no esperes más e inmediatamente escribe la salida".
                      fgets lee hasta 4096 bytes del stream de entrada

                      de aqui------------>

                      if (preg_match("/^([0-9]{1,3}) (.*)/", $data, $matches)) {
                      if (preg_match('/^result=([0-9a-zA-Z]*)( ?\((.*)\))?$/', $matches[2], $match)) {
                      $arr['code'] = $matches[1];
                      $arr['result'] = $match[1];
                      hasta aqui --------> limpiando para ver que hay en $data!!!!
                      Algo así. Estás 'filtrando' la salida de Asterisk y estás guardando lo que te itneresa para interpretarlo después.
                      de aqui ----------------->
                      switch($arr['result'])
                      {
                      case -1: $arr['data'] = trim("There is no channel that matches $channel"); break;
                      case AST_STATE_DOWN: $arr['data'] = 'Channel is down and available'; break;
                      case AST_STATE_RESERVED: $arr['data'] = 'Channel is down, but reserved'; break;
                      case AST_STATE_OFFHOOK: $arr['data'] = 'Channel is off hook'; break;
                      case AST_STATE_DIALING: $arr['data'] = 'Digits (or equivalent) have been dialed'; break;
                      case AST_STATE_RING: $arr['data'] = 'Line is ringing'; break;
                      case AST_STATE_RINGING: $arr['data'] = 'Remote end is ringing'; break;
                      case AST_STATE_UP: $arr['data'] = 'Line is up'; break;
                      case AST_STATE_BUSY: $arr['data'] = 'Line is busy'; break;
                      case AST_STATE_DIALING_OFFHOOK: $arr['data'] = 'Digits (or equivalent) have been dialed while offhook'; break;
                      case AST_STATE_PRERING: $arr['data'] = 'Channel has detected an incoming call and is waiting for ring'; break;
                      default: $arr['data'] = "Unknown ({$arr['result']})"; break;
                      }

                      hasta aqui------------> identificas y clasificas el resultado de $data
                      Exactamente

                      de aqui -------->

                      if (isset($match[3]) && $match[3])
                      $arr['data'] = $match[3];
                      return $arr;
                      } else return 0;
                      } else return -1;
                      }
                      hasta aqui-----> ni idea
                      Si si se encontró un dato en específico, regresa el dato que encontró. De lo contrario, regresa códigos 0 o -1 para indicar lo que pasó.

                      Te recomiendo consultes el manual de PHP en php.net para que puedas ver bien que hace cada función. Lo de los AGIs no es tan complicado, si ya sabes programar en algún idioma, claro está.

                      Saludos,
                      dCAP Christian Cabrera R.
                      Para aprender a usar Asterisk, asiste a uno de mis cursos Asterisk
                      Si deseas asesoría pagada, por favor contáctame

                      Comentario


                      • #12
                        Gracias sres

                        la verdad hasta cierto punto tienen razon,se de programacion pero no de php ni de agi.

                        conocen algun "manual" de agi

                        basicamete cualquier lenguaje tiene comandos y una estructura
                        pero de agi no conozco nada ycada vez queveo un codigo haycosas que nose que son
                        if (preg_match("/^([0-9]{1,3}) (.*)/", $data, por ejemplo.... es obvio queaqui se esta preguntando algo, pero /^ por ejemplo que hace...me entienden...
                        necesito info sobre esto .... simepudieran alludar ....gracias

                        NOTA: lo que necesito hacer es : llamar a un numero xxxx que conteste un ivr, pida un codigo que busque este codigo en una base de datos y que si encuentra el registro almacene la infode ese registro para ser presentada en una pagina web....

                        Gracias
                        Bastian_x

                        Comentario


                        • #13
                          Lo que quieres es muy sencillo, pero hazlo en otro tema.

                          Lo de preg_match("/^([0-9]{1,3}) (.*)/", $data) es la búsqueda de una expresión regular en PHP. Las expresiones regulares (o REGEXP) son muy comunes en Linux y se usan mucho en PHP y Perl.

                          Tu no necesitas un manual de AGI (porque como tal, no lo hay), pero puedes conseguir el de PHP desde http://php.net, bajo documentation.

                          Saludos,
                          dCAP Christian Cabrera R.
                          Para aprender a usar Asterisk, asiste a uno de mis cursos Asterisk
                          Si deseas asesoría pagada, por favor contáctame

                          Comentario


                          • #14
                            hola a todos

                            estoy recien investigando acerca de los agi, conozco php, puedo que mi pregunta se evidente pero como ejecuto un agi, se que se llama desde una extension pero, basta solo copiar el script en /var/lib/asterisk/agi-bin o hay que instalarle algun modulo php, estuve investigando sobre Agiphp, pero la verdad es que estoy medio desorientado.

                            de ante mano gracias

                            Comentario


                            • #15
                              no hace falta instalar ningun modulo, simplemente seguir los ejemplo de voip-info.org, pero si ya sabes PHP no te va a ser dificil.

                              SAludos

                              Comentario

                              Principales Usuarios Activos

                              Colapsar

                              No hay usuarios activos superiores.
                              Trabajando...
                              X