<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Dr. Danguer y Mr. Daniel &#187; PHP</title>
	<atom:link href="http://vida.danguer.com/category/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://vida.danguer.com</link>
	<description>Un blog más de un freelancer</description>
	<lastBuildDate>Sun, 31 Jan 2010 00:14:20 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.6</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Cuidado al usar Zend_Date</title>
		<link>http://vida.danguer.com/2010/01/30/cuidado-al-usar-zend_date/</link>
		<comments>http://vida.danguer.com/2010/01/30/cuidado-al-usar-zend_date/#comments</comments>
		<pubDate>Sun, 31 Jan 2010 00:14:20 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Trabajo]]></category>
		<category><![CDATA[Fechas]]></category>
		<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[Zend_Date]]></category>

		<guid isPermaLink="false">http://vida.danguer.com/?p=96</guid>
		<description><![CDATA[<p>En un proyecto, estaba utilizando Zend_Date para manejo de horas en diferentes zonas horarias, cuando lo estaba desarrollando empecé a tener un error porque olvidé que la fecha se actualiza cuando cambias un parámetro y el problema surge cuando cambias el mes o día y se encuentra con una fecha inexistente aunque en el código parezca correcta, por ejemplo, supongamos que estamos en el mes de febrero y queremos crear una fecha de marzo (asignaré la fecha para reproducir el error, aunque el error es cuando se utiliza la fecha actual)</p>
<pre name="code" class="php">include_once("Zend/Date.php");
$fecha_febrero = mktime(0, 0, 0, 2, 1, 2010);
$fecha = new Zend_Date($fecha_febrero);
$fecha-&#62;setDay(31);
$fecha-&#62;setMonth(3);
print "Fecha Marzo: ".date("d/m/Y", $fecha-&#62;getTimestamp());</pre>
<p>Uno esperaría que el resultado fuera: <strong>31/03/2010</strong></p>
<p>Pero en su lugar mostrará <strong>03/03/2010</strong></p>
<p>Esto es porque al hacer <code>$fecha-&#62;setDay(31)</code> el sistema intenta crear la fecha: <strong>31/02/2010</strong> que no existe, por lo que &#8220;recorre&#8221; los días restantes para quedar en <strong>03/03/2010</strong>, al asignar el mes, no tiene efecto.</p>
<p>La solución es simplemente hacerlo en orden inverso:</p>
<pre name="code" class="php">include_once("Zend/Date.php");
$fecha_febrero = mktime(0, 0, 0, 2, 1, 2010);
$fecha = new Zend_Date($fecha_febrero);
$fecha-&#62;setMonth(3);
$fecha-&#62;setDay(31);
print "Fecha Marzo: ".date("d/m/Y", $fecha-&#62;getTimestamp());</pre>
<p>Eso parecería la solución ideal (y es la recomendada por la documentación), pero no es totalmente cierta, si por ejemplo estamos en enero 31 del 2010 e intentamos asignar una fecha de febrero, siempre obtendremos una fecha de marzo:</p>
<pre name="code" class="php">include_once 'Zend/Date.php';
$fecha_enero = mktime(0, 0, 0, 1, 31, 2010);
$fecha = new Zend_Date($fecha_enero);
$fecha-&#62;setMonth(2);
$fecha-&#62;setDay(10);
print "Fecha Febrero: ".date("d/m/Y", $fecha-&#62;getTimestamp());</pre>
<p>Uno esperaría que mostrara la fecha:<br />
<strong>10/02/2010</strong></p>
<p>Pero en realidad muestra<br />
<strong>10/03/2010</strong></p>
<p>Esto porque cuando asignamos el mes, el sistema intenta crear la fecha 31/03/2010 que una vez más es incorrecta, por lo que crea la fecha 03/03/2010, pero al asignar la fecha, el resultado es un error en el mes.</p>
<p>Aunque esto no es un error, es muy peligroso porque uno puede suponer que la fecha es correcta porque&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>En un proyecto, estaba utilizando Zend_Date para manejo de horas en diferentes zonas horarias, cuando lo estaba desarrollando empecé a tener un error porque olvidé que la fecha se actualiza cuando cambias un parámetro y el problema surge cuando cambias el mes o día y se encuentra con una fecha inexistente aunque en el código parezca correcta, por ejemplo, supongamos que estamos en el mes de febrero y queremos crear una fecha de marzo (asignaré la fecha para reproducir el error, aunque el error es cuando se utiliza la fecha actual)</p>
<pre name="code" class="php">include_once("Zend/Date.php");
$fecha_febrero = mktime(0, 0, 0, 2, 1, 2010);
$fecha = new Zend_Date($fecha_febrero);
$fecha-&gt;setDay(31);
$fecha-&gt;setMonth(3);
print "Fecha Marzo: ".date("d/m/Y", $fecha-&gt;getTimestamp());</pre>
<p>Uno esperaría que el resultado fuera: <strong>31/03/2010</strong></p>
<p>Pero en su lugar mostrará <strong>03/03/2010</strong></p>
<p>Esto es porque al hacer <code>$fecha-&gt;setDay(31)</code> el sistema intenta crear la fecha: <strong>31/02/2010</strong> que no existe, por lo que &#8220;recorre&#8221; los días restantes para quedar en <strong>03/03/2010</strong>, al asignar el mes, no tiene efecto.</p>
<p>La solución es simplemente hacerlo en orden inverso:</p>
<pre name="code" class="php">include_once("Zend/Date.php");
$fecha_febrero = mktime(0, 0, 0, 2, 1, 2010);
$fecha = new Zend_Date($fecha_febrero);
$fecha-&gt;setMonth(3);
$fecha-&gt;setDay(31);
print "Fecha Marzo: ".date("d/m/Y", $fecha-&gt;getTimestamp());</pre>
<p>Eso parecería la solución ideal (y es la recomendada por la documentación), pero no es totalmente cierta, si por ejemplo estamos en enero 31 del 2010 e intentamos asignar una fecha de febrero, siempre obtendremos una fecha de marzo:</p>
<pre name="code" class="php">include_once 'Zend/Date.php';
$fecha_enero = mktime(0, 0, 0, 1, 31, 2010);
$fecha = new Zend_Date($fecha_enero);
$fecha-&gt;setMonth(2);
$fecha-&gt;setDay(10);
print "Fecha Febrero: ".date("d/m/Y", $fecha-&gt;getTimestamp());</pre>
<p>Uno esperaría que mostrara la fecha:<br />
<strong>10/02/2010</strong></p>
<p>Pero en realidad muestra<br />
<strong>10/03/2010</strong></p>
<p>Esto porque cuando asignamos el mes, el sistema intenta crear la fecha 31/03/2010 que una vez más es incorrecta, por lo que crea la fecha 03/03/2010, pero al asignar la fecha, el resultado es un error en el mes.</p>
<p>Aunque esto no es un error, es muy peligroso porque uno puede suponer que la fecha es correcta porque en el código lo parece, la solución sin embargo es trivial, asignar el primer día de un mes que tenga 31 días y asignar los valores en orden inverso (primero año, luego mes y por último día), así el código sin error sería:</p>
<pre name="code" class="php">
include_once 'Zend/Date.php';
$fecha = new Zend_Date(0, 0, 0, 1, 1, date('Y'));
$fecha-&gt;setMonth(2);
$fecha-&gt;setDay(10);
print "Fecha Febrero: ".date("d/m/Y", $fecha-&gt;getTimestamp());
</pre>
<p>Resultado (el esperado)<br />
<strong>10/02/2010</strong></p>
<p>Esto funciona en la mayoría de los casos; aunque si van a manejar diferentes zonas horarias mediante <code>setTimezone()</code> el código anterior tendrá el mismo error en los casos que la zona horaria sea menor a la zona horaria del servidor, por lo que hay que hacer algo más elaborado:</p>
<pre name="code" class="php">
include_once 'Zend/Date.php';
$fecha = new Zend_Date();
//eliminar "errores"
$fecha-&gt;setTimezone('mi_codigo_zona_horaria');
$fecha-&gt;setDay(1);
$fecha-&gt;setMonth(1);

//nuestro código
$fecha-&gt;setMonth(2);
$fecha-&gt;setDay(10);
print "Fecha Febrero: ".date("d/m/Y", $fecha-&gt;getTimestamp());
</pre>
<p>Lo peligroso del comportamiento de Zend_Date es que funcionará con errores durante algunos días/meses dependiendo de la manera en como se programe y es un poco difícil de diagnosticar por su misma naturaleza, con esto se elimina cualquier tipo de errores.</p>
]]></content:encoded>
			<wfw:commentRss>http://vida.danguer.com/2010/01/30/cuidado-al-usar-zend_date/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Tip Rápido: Completación de código en Zend Studio</title>
		<link>http://vida.danguer.com/2009/03/31/tip-rapido-completacion-de-codigo-en-zend-studio/</link>
		<comments>http://vida.danguer.com/2009/03/31/tip-rapido-completacion-de-codigo-en-zend-studio/#comments</comments>
		<pubDate>Tue, 31 Mar 2009 23:08:23 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend Studio]]></category>

		<guid isPermaLink="false">http://vida.danguer.com/?p=93</guid>
		<description><![CDATA[<p>Uso mucho el <a title="Zend Studio" href="http://www.zend.com/en/products/studio/" target="_blank">Zend Studio</a>, aunque la primera versión fue desastrosa a partir de la 6.0.1 se han esmerado muchísimo; lo único malo que me he topado es que al hacer un proyecto Zend Framework se vuelve terriblemente lento y que tiene un poco de código extra poco necesario en su plantilla; aunque la ventaja es que ya trae ejemplos de Unit Test Case para los modelos (falta probarlos a detalle =P)</p>
<p>Usualmente al construir mis clases no pongo mucha documentación por función, por tanto Zend Studio no puede &#8220;determinar&#8221; qué tipo de variable regresa esa función. </p>
<p>Para facilitar esto, lo que hago es simplemente agregar este pedazo de código:</p>
<pre name="code" class="php">
    /**
     * @return Zend_Db_Adapter_Abstract
     */
	public static function getDB() {
             /* ... aqui va el código */
         }
 </pre>
<p>Básicamente es el snippet de código para documentación pero usando solamente el tipo de objeto que regresa la función.<br />
Con esto cuando utilices la función, Zend Studio podrá fácilmente mostrarte las propiedades y métodos del objeto.</p>
]]></description>
			<content:encoded><![CDATA[<p>Uso mucho el <a title="Zend Studio" href="http://www.zend.com/en/products/studio/" target="_blank">Zend Studio</a>, aunque la primera versión fue desastrosa a partir de la 6.0.1 se han esmerado muchísimo; lo único malo que me he topado es que al hacer un proyecto Zend Framework se vuelve terriblemente lento y que tiene un poco de código extra poco necesario en su plantilla; aunque la ventaja es que ya trae ejemplos de Unit Test Case para los modelos (falta probarlos a detalle =P)</p>
<p>Usualmente al construir mis clases no pongo mucha documentación por función, por tanto Zend Studio no puede &#8220;determinar&#8221; qué tipo de variable regresa esa función. </p>
<p>Para facilitar esto, lo que hago es simplemente agregar este pedazo de código:</p>
<pre name="code" class="php">
    /**
     * @return Zend_Db_Adapter_Abstract
     */
	public static function getDB() {
             /* ... aqui va el código */
         }
 </pre>
<p>Básicamente es el snippet de código para documentación pero usando solamente el tipo de objeto que regresa la función.<br />
Con esto cuando utilices la función, Zend Studio podrá fácilmente mostrarte las propiedades y métodos del objeto.</p>
]]></content:encoded>
			<wfw:commentRss>http://vida.danguer.com/2009/03/31/tip-rapido-completacion-de-codigo-en-zend-studio/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>TinyURL API &#8211; Snippet</title>
		<link>http://vida.danguer.com/2009/03/23/tinyurl-api-snippet/</link>
		<comments>http://vida.danguer.com/2009/03/23/tinyurl-api-snippet/#comments</comments>
		<pubDate>Mon, 23 Mar 2009 18:39:44 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Snippet]]></category>

		<guid isPermaLink="false">http://vida.danguer.com/?p=92</guid>
		<description><![CDATA[<p>Aqui hay un snippet (pedazo de código) para utilizar el API de TinyURL (TinyAPI <img src='http://vida.danguer.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  ), básicamente es llamar a la siguiente dirección:</p>
<pre name="code" class="php">
http://tinyurl.com/api-create.php?url= 
</pre>
<p>y agregar al final la URL que queremos &#8220;achicar&#8221; con TinyURL, la página regresará como único contenido la URL nueva, por ejemplo:<br />
<a href="http://tinyurl.com/api-create.php?url=http://vida.danguer.com">http://tinyurl.com/api-create.php?url=http://vida.danguer.com</a></p>
<p>Da como resultado:<br />
<a href="http://tinyurl.com/dfz9c3">http://tinyurl.com/dfz9c3</a></p>
<p>El snippet para PHP es el siguiente: </p>
<pre name="code" class="php">
function get_tinyurl($url) {
     $url = "http://tinyurl.com/api-create.php?url=".urlencode($url);
     return trim(file_get_contents($url));
}
</pre>
<p> </p>
<p>Demasiado facil, no? solamente hay que invocarlo como:</p>
<pre name="code" class="php">
get_tinyurl('http://vida.danguer.com')
</pre>
<p>y obtendremos la nueva URL.</p>
]]></description>
			<content:encoded><![CDATA[<p>Aqui hay un snippet (pedazo de código) para utilizar el API de TinyURL (TinyAPI <img src='http://vida.danguer.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  ), básicamente es llamar a la siguiente dirección:</p>
<pre name="code" class="php">
http://tinyurl.com/api-create.php?url= 
</pre>
<p>y agregar al final la URL que queremos &#8220;achicar&#8221; con TinyURL, la página regresará como único contenido la URL nueva, por ejemplo:<br />
<a href="http://tinyurl.com/api-create.php?url=http://vida.danguer.com">http://tinyurl.com/api-create.php?url=http://vida.danguer.com</a></p>
<p>Da como resultado:<br />
<a href="http://tinyurl.com/dfz9c3">http://tinyurl.com/dfz9c3</a></p>
<p>El snippet para PHP es el siguiente: </p>
<pre name="code" class="php">
function get_tinyurl($url) {
     $url = "http://tinyurl.com/api-create.php?url=".urlencode($url);
     return trim(file_get_contents($url));
}
</pre>
<p> </p>
<p>Demasiado facil, no? solamente hay que invocarlo como:</p>
<pre name="code" class="php">
get_tinyurl('http://vida.danguer.com')
</pre>
<p>y obtendremos la nueva URL.</p>
]]></content:encoded>
			<wfw:commentRss>http://vida.danguer.com/2009/03/23/tinyurl-api-snippet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Obtener video FLV de YouTube</title>
		<link>http://vida.danguer.com/2009/01/09/obtener-video-flv-de-youtube/</link>
		<comments>http://vida.danguer.com/2009/01/09/obtener-video-flv-de-youtube/#comments</comments>
		<pubDate>Fri, 09 Jan 2009 21:02:59 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[FLV]]></category>
		<category><![CDATA[YouTube]]></category>

		<guid isPermaLink="false">http://vida.danguer.com/?p=89</guid>
		<description><![CDATA[<p>Esta es la nueva manera de obtener el video de YouTube, los parámetros para <code>get_video.php</code> quedan iguales (<code>video_id</code> y <code>t</code>), pero <code>t</code> cambia y ahora no se obtiene al cargar el video, se tiene que llamar a otra URL para obtener esa información.</p>
<p>El método es muy fácil, los pasos son:</p>
<ol>
<li>Llamar a: <br />
<code>http://www.youtube.com/get_video_info.php?video_id=VIDEOID</code><br />
Donde <code>VIDEOID</code> es el id del video que vamos a obtener el archivo <code>FLV</code> (las ligas de YouTube para ver el video son como: <code>http://www.youtube.com/v/VIDEOID</code>)<br />
Tomaremos por ejemplo este:<br />
<code>http://www.youtube.com/get_video_info.php?video_id=HDi9OeJqwG4</code> </li>
<li>El resultado será en texto y tendrá muchas variables como:
<pre name="code" class="php">status=ok&#38;title=Rob+Dougan+-+Furious+Angels&#38;muted=0&#38;avg_rating=4.8496592845&#38;creator=eitch&#38;length_seconds=237&#38;vq=None&#38;fmt_map=&#38;token=OEgsToPDskKxBcum6P4BEStM-z3qkYZW&#38;thumbnail_url=http%3A%2F%2Fi1.ytimg.com%2Fvi%2FHDi9OeJqwG4%2Fdefault.jpg&#38;allow_ratings=True&#38;plid=AARgErHUJPLX2RPWAAAAoABoIAE&#38;track_embed=1</pre>
</li>
<li>De aqui solamente necesitamos obtener el parámetro <code>token</code> y pasarlo al ya conocido <code>get_video.php</code>:<br />
<code>http://www.youtube.com/get_video.php?video_id=HDi9OeJqwG4&#38;t=OEgsToPDskKxBcum6P4BEStM-z3qkYZW</code></li>
</ol>
<p>Con esto ya obtendremos el FLV deseado, en PHP la rutina sería la siguiente:</p>
<pre name="code" class="php">&#60;?php
//video id por defecto
$video_id = 'HDi9OeJqwG4';

if (isset($_REQUEST['video_id']))
        $video_id = trim($_REQUEST['video_id']);

//obtener informacion
$url_info = 'http://www.youtube.com/get_video_info.php?video_id='.$video_id;
$info = file_get_contents($url_info);

$vars = array();
parse_str($info, $vars);

$url_flv = 'http://www.youtube.com/get_video.php?video_id='.$video_id.'&#38;t='.$var
s['token'];

print 'Archivo FLV: '.$url_flv;
?&#62;</pre>
<p>Con esto obtenemos la URL del archivo <code>FLV</code>.</p>
<p>Es importante notar que en Flex/Flash no se podrá cargar diréctamente <code>get_video_info.php</code> por la política del <code>crossdomain</code> de YouTube así que hay que utilizar un proxy.</p>
<p>El demo lo pueden probar desde:<br />
<a href="http://demo.livesourcing.com/blog_vida/articulos/DanguerArticle_Youtube/">http://demo.livesourcing.com/blog_vida/articulos/DanguerArticle_Youtube/?video_id=VIDEOID</a><br />
Donde VIDEOID es el id del video de YouTube de su preferencia =)</p>
<p>El código fuente lo pueden descargar de:<br />
<a href="http://demo.livesourcing.com/blog_vida/articulos/DanguerArticle_Youtube.tar.gz">http://demo.livesourcing.com/blog_vida/articulos/DanguerArticle_Youtube.tar.gz</a><br />
 </p>
<p> </p>
<p> </p>
<p> </p>
]]></description>
			<content:encoded><![CDATA[<p>Esta es la nueva manera de obtener el video de YouTube, los parámetros para <code>get_video.php</code> quedan iguales (<code>video_id</code> y <code>t</code>), pero <code>t</code> cambia y ahora no se obtiene al cargar el video, se tiene que llamar a otra URL para obtener esa información.</p>
<p>El método es muy fácil, los pasos son:</p>
<ol>
<li>Llamar a: <br />
<code>http://www.youtube.com/get_video_info.php?video_id=VIDEOID</code><br />
Donde <code>VIDEOID</code> es el id del video que vamos a obtener el archivo <code>FLV</code> (las ligas de YouTube para ver el video son como: <code>http://www.youtube.com/v/VIDEOID</code>)<br />
Tomaremos por ejemplo este:<br />
<code>http://www.youtube.com/get_video_info.php?video_id=HDi9OeJqwG4</code> </li>
<li>El resultado será en texto y tendrá muchas variables como:
<pre name="code" class="php">status=ok&amp;title=Rob+Dougan+-+Furious+Angels&amp;muted=0&amp;avg_rating=4.8496592845&amp;creator=eitch&amp;length_seconds=237&amp;vq=None&amp;fmt_map=&amp;token=OEgsToPDskKxBcum6P4BEStM-z3qkYZW&amp;thumbnail_url=http%3A%2F%2Fi1.ytimg.com%2Fvi%2FHDi9OeJqwG4%2Fdefault.jpg&amp;allow_ratings=True&amp;plid=AARgErHUJPLX2RPWAAAAoABoIAE&amp;track_embed=1</pre>
</li>
<li>De aqui solamente necesitamos obtener el parámetro <code>token</code> y pasarlo al ya conocido <code>get_video.php</code>:<br />
<code>http://www.youtube.com/get_video.php?video_id=HDi9OeJqwG4&amp;t=OEgsToPDskKxBcum6P4BEStM-z3qkYZW</code></li>
</ol>
<p>Con esto ya obtendremos el FLV deseado, en PHP la rutina sería la siguiente:</p>
<pre name="code" class="php">&lt;?php
//video id por defecto
$video_id = 'HDi9OeJqwG4';

if (isset($_REQUEST['video_id']))
        $video_id = trim($_REQUEST['video_id']);

//obtener informacion
$url_info = 'http://www.youtube.com/get_video_info.php?video_id='.$video_id;
$info = file_get_contents($url_info);

$vars = array();
parse_str($info, $vars);

$url_flv = 'http://www.youtube.com/get_video.php?video_id='.$video_id.'&amp;t='.$var
s['token'];

print 'Archivo FLV: '.$url_flv;
?&gt;</pre>
<p>Con esto obtenemos la URL del archivo <code>FLV</code>.</p>
<p>Es importante notar que en Flex/Flash no se podrá cargar diréctamente <code>get_video_info.php</code> por la política del <code>crossdomain</code> de YouTube así que hay que utilizar un proxy.</p>
<p>El demo lo pueden probar desde:<br />
<a href="http://demo.livesourcing.com/blog_vida/articulos/DanguerArticle_Youtube/">http://demo.livesourcing.com/blog_vida/articulos/DanguerArticle_Youtube/?video_id=VIDEOID</a><br />
Donde VIDEOID es el id del video de YouTube de su preferencia =)</p>
<p>El código fuente lo pueden descargar de:<br />
<a href="http://demo.livesourcing.com/blog_vida/articulos/DanguerArticle_Youtube.tar.gz">http://demo.livesourcing.com/blog_vida/articulos/DanguerArticle_Youtube.tar.gz</a><br />
 </p>
<p> </p>
<p> </p>
<p> </p>
]]></content:encoded>
			<wfw:commentRss>http://vida.danguer.com/2009/01/09/obtener-video-flv-de-youtube/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Tips de PHP: Funciones para el manejo de Nombres de Archivo</title>
		<link>http://vida.danguer.com/2008/11/12/tips-de-php-funciones-para-el-manejo-de-nombres-de-archivo/</link>
		<comments>http://vida.danguer.com/2008/11/12/tips-de-php-funciones-para-el-manejo-de-nombres-de-archivo/#comments</comments>
		<pubDate>Wed, 12 Nov 2008 19:38:47 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[basename]]></category>
		<category><![CDATA[dirname]]></category>
		<category><![CDATA[pathinfo]]></category>
		<category><![CDATA[Tips]]></category>

		<guid isPermaLink="false">http://vida.danguer.com/?p=84</guid>
		<description><![CDATA[<p>Hay tres funciones en PHP que ayudan mucho para programar, las tres tienen que ver con el manejo de nombres de archivo (no con el archivo en si), estas son:</p>
<p><code><strong>basename($cadena[, $sufijo])</strong></code><br />
Regresa el nombre del archivo o directorio, por ejemplo:</p>
<pre name="code" class="php">
&#60;?php
basename('/var/www/index.html'); //regresa 'index.html'
basename('/var/www'); //regresa 'www'
?&#62;
</pre>
<p>Adicionalmente si se le pasa un segundo parámetro se removerá el sufijo si es que existe por ejemplo:</p>
<pre name="code" class="php">
&#60;?php
basename('/var/www/index.html', '.html'); //regresa 'index'
?&#62;
</pre>
<p><code><strong>dirname($cadena)</strong></code><br />
Regresa el nombre del directorio padre del archivo o directorio, es decir regresa lo opuesto a <code>basename</code></p>
<pre name="code" class="php">
&#60;?php
dirname('/var/www/index.html'); //regresa '/var/www'
dirname('/var/www'); //regresa '/var'
?&#62;
</pre>
<p>Debe notarse que no regresará el último separador (/)</p>
<p><code><strong>pathinfo($cadena[, $opciones])</strong></code><br />
Regresa información del archivo, si no se le pasan opciones regresa un arreglo con las siguientes llaves:<br />
<strong>dirname</strong>: nombre del directorio, es la misma salida de <code>dirname($cadena)</code><br />
<strong>basename</strong>: nombre del archivo, es la misma salida de <code>basename($cadena)</code><br />
<strong>extension</strong>: Si la extensión existe estará presente y será la extensión del archivo (cadena a partir del último .)<br />
<strong>filename</strong>: nombre del archivo sin extension</p>
<p>Por ejemplo:</p>
<pre name="code" class="php">
&#60;?php

pathinfo('/var/www/index.html');
/*
regresa:
Array
(
    [dirname] => /var/www
    [basename] => index.html
    [extension] => html
    [filename] => index
)
*/

pathinfo('/var/www/index');
/*
regresa:
Array
(
    [dirname] => /var/www
    [basename] => index
    [filename] => index
)
*/

pathinfo('/var/www/index.inc.php');
/*
regresa:
Array
(
    [dirname] => /var/www
    [basename] => index.inc.php
    [extension] => php
    [filename] => index.inc
)
*/

pathinfo('/var/www');
/*
regresa:
Array
(
    [dirname] => /var
    [basename] => www
    [filename] => www
)
*/

?&#62;
</pre>
<p>Adicionalmente se puede pasar una constante como parámetro para especificar unicamente un valor, en este caso la función regresa una cadena solamente; las constantes posibles son:</p>
<ul>
<li><code>PATHINFO_DIRNAME</code></li>
<li><code>PATHINFO_BASENAME</code></li>
<li><code>PATHINFO_EXTENSION</code></li>
<li><code>PATHINFO_FILENAME</code></li>
</ul>
<p>De los cuales, solamente son útiles: <code>PATHINFO_EXTENSION</code> y <code>PATHINFO_FILENAME</code> ya que <code>PATHINFO_DIRNAME</code> es equivalente a <code>dirname</code> y <code>PATHINFO_BASENAME</code> es equivalente a <code>basename</code></p>
<p><code>PATHINFO_FILENAME</code> evitar hacer dos llamadas (una a <code>filepath</code> para saber la extensión y la siguiente a <code>basename</code> con la extensión como sufijo para saber el nombre del archivo)</p>
<p>Ejemplo:</p>
<pre name="code" class="php">
&#60;?php

pathinfo('/var/www/index.html', PATHINFO_EXTENSION); //regresa 'html'
pathinfo('/var/www/index.html', PATHINFO_FILENAME); //regresa 'index'
?&#62;
</pre>
&#8230;]]></description>
			<content:encoded><![CDATA[<p>Hay tres funciones en PHP que ayudan mucho para programar, las tres tienen que ver con el manejo de nombres de archivo (no con el archivo en si), estas son:</p>
<p><code><strong>basename($cadena[, $sufijo])</strong></code><br />
Regresa el nombre del archivo o directorio, por ejemplo:</p>
<pre name="code" class="php">
&lt;?php
basename('/var/www/index.html'); //regresa 'index.html'
basename('/var/www'); //regresa 'www'
?&gt;
</pre>
<p>Adicionalmente si se le pasa un segundo parámetro se removerá el sufijo si es que existe por ejemplo:</p>
<pre name="code" class="php">
&lt;?php
basename('/var/www/index.html', '.html'); //regresa 'index'
?&gt;
</pre>
<p><code><strong>dirname($cadena)</strong></code><br />
Regresa el nombre del directorio padre del archivo o directorio, es decir regresa lo opuesto a <code>basename</code></p>
<pre name="code" class="php">
&lt;?php
dirname('/var/www/index.html'); //regresa '/var/www'
dirname('/var/www'); //regresa '/var'
?&gt;
</pre>
<p>Debe notarse que no regresará el último separador (/)</p>
<p><code><strong>pathinfo($cadena[, $opciones])</strong></code><br />
Regresa información del archivo, si no se le pasan opciones regresa un arreglo con las siguientes llaves:<br />
<strong>dirname</strong>: nombre del directorio, es la misma salida de <code>dirname($cadena)</code><br />
<strong>basename</strong>: nombre del archivo, es la misma salida de <code>basename($cadena)</code><br />
<strong>extension</strong>: Si la extensión existe estará presente y será la extensión del archivo (cadena a partir del último .)</code><br />
<strong>filename</strong>: nombre del archivo sin extension</code></p>
<p>Por ejemplo:</p>
<pre name="code" class="php">
&lt;?php

pathinfo('/var/www/index.html');
/*
regresa:
Array
(
    [dirname] => /var/www
    [basename] => index.html
    [extension] => html
    [filename] => index
)
*/

pathinfo('/var/www/index');
/*
regresa:
Array
(
    [dirname] => /var/www
    [basename] => index
    [filename] => index
)
*/

pathinfo('/var/www/index.inc.php');
/*
regresa:
Array
(
    [dirname] => /var/www
    [basename] => index.inc.php
    [extension] => php
    [filename] => index.inc
)
*/

pathinfo('/var/www');
/*
regresa:
Array
(
    [dirname] => /var
    [basename] => www
    [filename] => www
)
*/

?&gt;
</pre>
<p>Adicionalmente se puede pasar una constante como parámetro para especificar unicamente un valor, en este caso la función regresa una cadena solamente; las constantes posibles son:</p>
<ul>
<li><code>PATHINFO_DIRNAME</code></li>
<li><code>PATHINFO_BASENAME</code></li>
<li><code>PATHINFO_EXTENSION</code></li>
<li><code>PATHINFO_FILENAME</code></li>
</ul>
<p>De los cuales, solamente son útiles: <code>PATHINFO_EXTENSION</code> y <code>PATHINFO_FILENAME</code> ya que <code>PATHINFO_DIRNAME</code> es equivalente a <code>dirname</code> y <code>PATHINFO_BASENAME</code> es equivalente a <code>basename</code></p>
<p><code>PATHINFO_FILENAME</code> evitar hacer dos llamadas (una a <code>filepath</code> para saber la extensión y la siguiente a <code>basename</code> con la extensión como sufijo para saber el nombre del archivo)</p>
<p>Ejemplo:</p>
<pre name="code" class="php">
&lt;?php

pathinfo('/var/www/index.html', PATHINFO_EXTENSION); //regresa 'html'
pathinfo('/var/www/index.html', PATHINFO_FILENAME); //regresa 'index'
?&gt;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://vida.danguer.com/2008/11/12/tips-de-php-funciones-para-el-manejo-de-nombres-de-archivo/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Certificación en Zend Framework</title>
		<link>http://vida.danguer.com/2008/10/08/certificacion-en-zend-framework/</link>
		<comments>http://vida.danguer.com/2008/10/08/certificacion-en-zend-framework/#comments</comments>
		<pubDate>Wed, 08 Oct 2008 15:24:34 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Trabajo]]></category>
		<category><![CDATA[Zend]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://vida.danguer.com/?p=76</guid>
		<description><![CDATA[<p>Hace poco Zend publicó la certificación de Zend Framework:<br />
<a href="http://www.zend.com/en/services/certification/framework/">http://www.zend.com/en/services/certification/framework/</a></p>
<p>Estoy algo divergente entre si es una buena opción o no</p>
<p>Buena opción:</p>
<ul>
<li>El Framework está muy bien hecho como para que valga una certificación</li>
<li>Tiene tantos componentes que es una buena medida para destacar entre los que han utilizado solamente brevemente el Framework</li>
</ul>
<p> </p>
<p>Mala opción</p>
<ul>
<li>Cuesta más que la certificación en PHP ($160 dolares en contra de $125 para la certificación de PHP)</li>
<li>Lamentablemente la certificación es en la versión 1.5 y la versión estable es la versión 1.6, si bien la versión 1.5 ya tenía muy estandarizado el modelo del Framework, a menos que tengan un periodo largo de liberar versiones (lo cual puede ser malo ya que ahora hay mucho movimiento) en menos de un año seguramente saldran al menos un par de versiones por lo que ¿se va a certificar en cada version? =P</li>
</ul>
<div>Tampoco hay guia oficial, solamente está la opción de curso.</div>
<div></div>
<div>Creo que el Zend Framework debe crecer un poco más para estabilizarse en cuestión de características generales y de ahi ya es una opción muy válida de certificación; ya que en el momento hay mucho movimiento en cuestión de nuevas características, por ejemplo la versión 1.6 la principal mejora fue la introducción de Dojo.</div>
<p> </p>
]]></description>
			<content:encoded><![CDATA[<p>Hace poco Zend publicó la certificación de Zend Framework:<br />
<a href="http://www.zend.com/en/services/certification/framework/">http://www.zend.com/en/services/certification/framework/</a></p>
<p>Estoy algo divergente entre si es una buena opción o no</p>
<p>Buena opción:</p>
<ul>
<li>El Framework está muy bien hecho como para que valga una certificación</li>
<li>Tiene tantos componentes que es una buena medida para destacar entre los que han utilizado solamente brevemente el Framework</li>
</ul>
<p> </p>
<p>Mala opción</p>
<ul>
<li>Cuesta más que la certificación en PHP ($160 dolares en contra de $125 para la certificación de PHP)</li>
<li>Lamentablemente la certificación es en la versión 1.5 y la versión estable es la versión 1.6, si bien la versión 1.5 ya tenía muy estandarizado el modelo del Framework, a menos que tengan un periodo largo de liberar versiones (lo cual puede ser malo ya que ahora hay mucho movimiento) en menos de un año seguramente saldran al menos un par de versiones por lo que ¿se va a certificar en cada version? =P</li>
</ul>
<div>Tampoco hay guia oficial, solamente está la opción de curso.</div>
<div></div>
<div>Creo que el Zend Framework debe crecer un poco más para estabilizarse en cuestión de características generales y de ahi ya es una opción muy válida de certificación; ya que en el momento hay mucho movimiento en cuestión de nuevas características, por ejemplo la versión 1.6 la principal mejora fue la introducción de Dojo.</div>
<p> </p>
]]></content:encoded>
			<wfw:commentRss>http://vida.danguer.com/2008/10/08/certificacion-en-zend-framework/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Como programar (decente) en PHP</title>
		<link>http://vida.danguer.com/2008/10/05/como-programar-decente-en-php/</link>
		<comments>http://vida.danguer.com/2008/10/05/como-programar-decente-en-php/#comments</comments>
		<pubDate>Sun, 05 Oct 2008 07:23:05 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Trabajo]]></category>
		<category><![CDATA[Tips]]></category>

		<guid isPermaLink="false">http://vida.danguer.com/?p=74</guid>
		<description><![CDATA[<p>El viernes un cliente me pidió un favor de ayudarle a terminar de instalar un script de un amigo en su servidor. </p>
<p>Todo parecía ser un simple problema con la importación de MySQL por los acentos, aunque eso solucionó parcialmente aún tenía un error en la parte medular del sistema, en cuanto abri el archivo que estaba dando el error me arrepentí de hacerlo y mi mente se volcó a recordar hace cinco años o tal vez seis cuando se programaba de esa manera =)</p>
<p>Con ese ejemplo me vino a la mente una frase célebre de mi buen amigo <a href="http://www.developarts.com" target="_blank">Nexus</a> en esas épocas cuando estaba aprendiendo a programar en PHP, mi geek interno terco siguió programando con las antiquísimas <code>$HTTP_POST_VARS</code> a pesar de que se habían desalentado utilizar esas variables y se reemplazó por las variables tipo: <code>$_POST</code> ó <code>$_GET</code></p>
<p>Recuerdo que cuando Nexus vio un código mio que tenía el <code>$HTTP_POST_VARS</code> me dijo en un chat con (me parece Carlos Cortez): &#8220;Programas a la manera viejita jajajaja&#8221;. Claro por orgullo después de eso nunca volví a tocar <code>$HTTP_POST_VARS</code></p>
<p>Aqui tengo unos consejos para que no solamente sea fácil programar, depurar y para otros leer tu código. También para evitar que PHP siga siendo visto como un lenguaje de &#8220;bajo presupuesto&#8221; (por aquello que muchos prefieren Java por lo &#8216;empresarial&#8217;)</p>
<p> </p>
<p><strong>Tip: PHP dejó de ser un lenguaje de Script hace años</strong></p>
<p>Lo digo en completo tono sarcástico, si bien PHP no se puede compilar no hay razón para meter todo dentro de un solo archivo como print&#8217;s con funciones, prácticamente se debe separar de preferencia en un modelo <strong>MVC</strong> si no puedes hacerlo, entonces al menos hazlo en <strong>VE</strong> (Vista-Espaguetti donde vas a meter tanto modelo como controlador)</p>
<p> </p>
<p><strong>Tip: <code>register_globals</code> está muerto</strong></p>
<p>Por eso me dio miedo abrir el archivo, necesitaba <code>register_globals</code>. Para el que no sepa que es <code>register_globals</code> es simplemente que cuando mandamos parámetros&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>El viernes un cliente me pidió un favor de ayudarle a terminar de instalar un script de un amigo en su servidor. </p>
<p>Todo parecía ser un simple problema con la importación de MySQL por los acentos, aunque eso solucionó parcialmente aún tenía un error en la parte medular del sistema, en cuanto abri el archivo que estaba dando el error me arrepentí de hacerlo y mi mente se volcó a recordar hace cinco años o tal vez seis cuando se programaba de esa manera =)</p>
<p>Con ese ejemplo me vino a la mente una frase célebre de mi buen amigo <a href="http://www.developarts.com" target="_blank">Nexus</a> en esas épocas cuando estaba aprendiendo a programar en PHP, mi geek interno terco siguió programando con las antiquísimas <code>$HTTP_POST_VARS</code> a pesar de que se habían desalentado utilizar esas variables y se reemplazó por las variables tipo: <code>$_POST</code> ó <code>$_GET</code></p>
<p>Recuerdo que cuando Nexus vio un código mio que tenía el <code>$HTTP_POST_VARS</code> me dijo en un chat con (me parece Carlos Cortez): &#8220;Programas a la manera viejita jajajaja&#8221;. Claro por orgullo después de eso nunca volví a tocar <code>$HTTP_POST_VARS</code></p>
<p>Aqui tengo unos consejos para que no solamente sea fácil programar, depurar y para otros leer tu código. También para evitar que PHP siga siendo visto como un lenguaje de &#8220;bajo presupuesto&#8221; (por aquello que muchos prefieren Java por lo &#8216;empresarial&#8217;)</p>
<p> </p>
<p><strong>Tip: PHP dejó de ser un lenguaje de Script hace años</strong></p>
<p>Lo digo en completo tono sarcástico, si bien PHP no se puede compilar no hay razón para meter todo dentro de un solo archivo como print&#8217;s con funciones, prácticamente se debe separar de preferencia en un modelo <strong>MVC</strong> si no puedes hacerlo, entonces al menos hazlo en <strong>VE</strong> (Vista-Espaguetti donde vas a meter tanto modelo como controlador)</p>
<p> </p>
<p><strong>Tip: <code>register_globals</code> está muerto</strong></p>
<p>Por eso me dio miedo abrir el archivo, necesitaba <code>register_globals</code>. Para el que no sepa que es <code>register_globals</code> es simplemente que cuando mandamos parámetros a un script como por ejemplo: <code>prueba.php?variable1=hola&amp;variable2=mundo</code> PHP convierte automáticamente esas dos variables en <code>$variable1</code> y <code>$variable2</code> con su respectivo contenido.</p>
<p>Qué fácil, ¿No?. Pues en realidad no, cuando el mundo no se percataba del error fatal de hacer esto, parecía que PHP era tan fácil de programar, vaya no necesitabas ni siquiera  vincular los parámetros.</p>
<p>Poco después un balde de agua fria cayó sobre todos nosotros&#8230; el problema es que cualquier tipo con algo de sesos puede simplemente pasar variables y asignar valores de la aplicación. En el caso de una aplicación que no inicializara las variables (el 99% para ser sinceros) podía sufrir porque era fácilmente &#8220;hackeada&#8221; sin necesidad de hacer mucho.</p>
<p>Por eso rápidamente se eliminó <code>register_globals</code> y se dejó como un parámetro opcional, pero muy opcional. Tanto que en PHP 6 va a desaparecer definitivamente. </p>
<p><code>register_globals</code> no ayuda, no hace más rápido el desarrollo; simplemente destruye todo lo bueno que podría tener una aplicación, porque en primer lugar es difícil saber cuales variables son parámetros del usuario y cuales son variables internas. También hace fácil explotar un sistema (creo que ya lo había dicho <img src='http://vida.danguer.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  ).</p>
<p>La solución para esto&#8230; reescribe tu aplicación.</p>
<p> </p>
<p><strong>Tip: <code>die()</code> está muerto</strong></p>
<p>¿Alguien se ha preguntado porqué existe esta construcción del lenguaje de PHP?, supongo que es un legado de los viejos días cuando PHP era un lenguaje de script.</p>
<p><code>die()</code> permite simplemente eso: hace que el script muera. Muchos lo hacían para verificar una situación intolerable como al abrir una conexión a una base de datos y que no se pudiera conectar; como no se pueden mostrar datos entonces simplemente le decimos al usuario: &#8220;perdon pero aqui nos detenemos&#8221; un ejemplo es el siguiente:</p>
<pre name="code" class="php">&lt;?php
    mysql_connect($host, $usuario, $password) or die('No pude conectarme a la base de datos');
?&gt;</pre>
<p>¿Cuál es el problema?, muy simple la función die funciona tan perfectamente que el script se muere ahi. Por lo que el usuario simplemente verá una pantalla blanca con un texto críptico. En el peor de los casos mostrará una parte de la página y la &#8220;cortará&#8221; donde se haya ejecutado esta instrucción.</p>
<p>No seas perezoso, utiliza construcciones de <code>if()</code> para separar bloques de instrucciones en vez de suicidarte.<br />
Si aún así quieres hacer un <code>die()</code> o un <code>exit()</code> al menos manda a llamar a una plantilla especial que muestre el error con la mayor parte del mismo estilo de la página que vas a mostrar, te lo agradecerá el usuario.</p>
<p> </p>
<p> </p>
<p><strong>Tip: <code>include</code> y <code>require</code> es un arma de dos filos</strong></p>
<p>También un legado de aquellos días es que un script luzca como:</p>
<pre name="code" class="php">&lt;?php include 'cabecera.php'; ?&gt;
&lt;?php print "Hola mundo 'plantilla'; ?&gt;
&lt;?php include 'pie_pagina.php'; ?&gt;</pre>
<p>En aquellos días estas eran nuestras plantillas, <code>cabecera.php</code> mostraba el código inicial de HTML y <code>pie_pagina.php</code> cerraba ese código HTML, qué facil, ¿verdad?</p>
<p>Pues no, el problema de este método es que en primer lugar las variables son globales y compartidas, por lo que si haces el código espaguetti anterior es un total NO.</p>
<p>Por ejemplo es fácil sobreescribir variables dentro de un archivo &#8220;plantilla&#8221; y el error se propaga a las otras &#8220;plantillas&#8221;.</p>
<p>Otro problema es que hacen difícil seguir un flujo real de plantillas (si no quieres una parte tienes que reescribir todo en lugar de simplemente cambiar por ejemplo la distribución de los objetos en una plantilla general. También es fácil de romper todo el HTML por una etiqueta fuera de lugar</p>
<p>Una vez más, no seas perezoso y utiliza un manejador de plantillas como <a href="http://www.smarty.net/">Smarty</a></p>
<p>Ahora bien del lado de programación un <code>include()</code> por lo regular es utilizado para incluir pedazos de código tales como funciones, clases, etc. Pero lamentablemente también es utilizado para incluir pedazos de código que tienen el mismo uso que funciones!!</p>
<p>Eso es algo totalmente prohibido, no se porque no utilizas funciones o mejor aún una clase.</p>
<p> </p>
<p><strong>Tip: <code>mysql_connect</code> y sus vicios</strong></p>
<p>Un legado también de aquellos días es que se programaba de la siguiente manera:</p>
<pre name="code" class="php">&lt;?php
include 'configuracion_db.php';
mysql_connect($host, $usuario, $password) or die('No pude conectarme a la base de datos');
?&gt;</pre>
<p>donde <code>configuracion_db.php</code> era simplemente:</p>
<pre name="code" class="php">&lt;?php 
$host = 'localhost';
$usuario = 'mi_usuario';
$password = 'mi_password';
?&gt; </pre>
<p>El primero se incluia prácticamente como cabecera para todas las páginas porque necesitaban acceso a la base de datos, y también se incluia dentro de otros bloques dentro de la misma página.</p>
<p>O peor aún, incluir en cada archivo los parámetros de configuración. Esto último es simplemente un caos y es no saber programar, así que toma un curso de programacion básica en otro lenguaje antes de programar en PHP <img src='http://vida.danguer.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Para el primer caso si bien es válido, es simplemente malo debido a que otro script puede fácilmente sobreescribir esas variables (o el mismo script por error). Aunque es utilizado, es muchísimo mejor utilizar un patron de diseño llamado: <strong>Singleton</strong></p>
<p>El <strong>Singleton</strong> es un patron de diseño muy simple, en términos de orientación a objetos es un método estático de una clase que regresa siempre la misma instancia de la clase. Es decir solamente existirá un objeto en todo el sistema y que lo creará ese método estático normalmente llamado: <code>obtenerInstancia()</code></p>
<p>En lenguaje de funciones es simplemente una función que regresará la misma variable (tendrá la misma dirección de memoria) cada vez que se llame, así que en lugar de hacer el primer ejemplo utiliza este:</p>
<pre name="code" class="php">&lt;?php
function obtenerConectorMysql() {
     static $conector_mysql = null; 
     if ($conector_mysql == null) {
         //aqui insertar las instrucciones para obtener el host, usuario y password, 
         // por ejemplo de un archivo o simplemente escribirlas aqui
         $conector _mysql = mysql_connect($host, $usuario, $password);
     } 

     return $conector_mysql;
}</pre>
<p> </p>
<p>Esto simplemente crea la primera vez que se llame el conector_mysql, después simplemente lo regresa por lo que no se crean diferentes instancias, es la misma conexión a MySQL</p>
<p>Si lo quieres hacer mediante clases, puedes utilizarlo algo similar como una llamada a una función estática o &#8220;envolverlo&#8221; en la clase que tengas para manejar la base de datos.</p>
<p><strong>Tip: La seguridad no es para sitios de comercio o bancos solamente</strong></p>
<p>Mucha gente piensa que debe hacer &#8220;seguro&#8221; un sitio solamente si va a tener operaciones monetarias. Nada más fuera de la realidad. </p>
<p>Todos los sitios necesitan seguridad para evitar que los ataques logren su resultado: hacer &#8220;explotar&#8221; la aplicación.</p>
<p>Evitando los errores más comunes tendrás una aplicación que si bien no es tan segura como la de la CIA (lease con sarcasmo) evitará el 90% de los ataques comunes.</p>
<ol>
<li>Al desarrollar una aplicación, recuerda que el usuario no es de fiar, por lo que todo lo que provenga del usuario puede ser alterado</li>
<li>Siempre verifica la información que el usuario envió mediante parámetros. Si es posible restringe mediante un arreglo de valores válidos, si no es posible entonces haz muchas verificaciones, por ejemplo en el caso de un archivo, elimina caracteres peligrosos como: &#8216;..&#8217; o &#8216;/&#8217; que pueden hacer que el sistema lea (o incluso escriba) un archivo muy diferente al planeado.<br />
Esto se hace indispensable si vas a utilizar una función poderosa como <code>include()</code> o acceso al archivo (como <code>fopen()</code> )</li>
<li>Nunca pongas datos importantes en una <code>cookie</code>, utiliza sesiones. Si lees datos de una <code>cookie</code> nunca asumas que por ser <code>cookie</code> es dificil de alterar<br />
Si los datos van a &#8220;perdurar&#8221; más alla de una sesión, entonces deja en la cookie un identificador único y guárdalo en la base de datos, de esta manera el usuario solo debe proveer su identificador y no otra información que pudiera ser alterada. </li>
<li>Siempre &#8220;escapa&#8221; las variables que vas a utilizar en una consulta a la base de datos, utiliza funciones como: <code>mysql_escape_string()</code>, si utilizas un framework la mayoría de ellos tienen una función para hacer esto (que terminan llamando a algo similar a la primera función)</li>
</ol>
<p> </p>
<p><strong>Tip: PHP5 no es una opción, es obligatorio &gt;=)</strong></p>
<p>No veas a PHP5 como una &#8220;extensión&#8221; o una versión más. El propósito de PHP5 es hacer una transición entre el mundo de scripts de código espaguetti a un sistema de clases muy bien separadas.</p>
<p>Aunque PHP5 aún permite programar sin clases y con solo funciones; si tienes la oportunidad no dudes en utilizar PHP5 con clases con todo lo nuevo que trae. La guia de estudio de Certificación Zend es un buen inicio. </p>
<p>PHP5 tiene un gran potencial y está esperando para ser plenamente utilizado, algunos frameworks ya están utilizando plenamente su potencial, entre ellos <a href="http://framework.zend.com" target="_blank">Zend Framework</a> que es altamente recomendable.</p>
<p> </p>
<p><strong>Último tip: MVC es lo único para web <img src='http://vida.danguer.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </strong></p>
<p>Si vas a desarrollar una aplicación en PHP que contenga todo lo que una aplicación web contiene (contenido en HTML, bases de datos, procesamiento, etc) simplemente utiliza un framework que tenga un diseño de MVC; los más conocidos son <a href="http://framework.zend.com" target="_blank">Zend Framework</a> (mi recomendación nuevamente) y <a href="http://cakephp.org/" target="_blank">CakePHP</a>, también están otros en rápido ascenso como <a href="http://www.symfony-project.org" target="_blank">Simfony</a> y <a href="http://codeigniter.com/" target="_blank">Code Igniter</a></p>
<p>También son de uso popular los CMS como <a href="http://drupal.org" target="_blank">drupal</a> y <a href="http://www.joomlaspanish.org" target="_blank">joomla</a>/<a href="http://www.mambohispano.org" target="_blank">mambo</a>, aunque ellos no proveen directamente el modelo MVC si proveen el modelo Vista-Espaguetti por lo que con un poco de trabajo extra puedes lograr algo similar a MVC</p>
<p> </p>
<p>En resumen PHP es un lenguaje muy poderoso y con historia; por lo que es fácilmente quedarse con las primeras formas de programar, pero con todos los nuevos desarrollos ahora si se puede empezar a hablar de un PHP a nivel empresarial (ya formalmente <img src='http://vida.danguer.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  )</p>
<p> </p>
]]></content:encoded>
			<wfw:commentRss>http://vida.danguer.com/2008/10/05/como-programar-decente-en-php/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Ejemplo de API de Yahoo/Weather.com</title>
		<link>http://vida.danguer.com/2008/09/27/ejemplo-de-api-de-yahoo-weather/</link>
		<comments>http://vida.danguer.com/2008/09/27/ejemplo-de-api-de-yahoo-weather/#comments</comments>
		<pubDate>Sun, 28 Sep 2008 00:58:48 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[AJAX]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Clima]]></category>
		<category><![CDATA[Yahoo]]></category>

		<guid isPermaLink="false">http://vida.danguer.com/?p=70</guid>
		<description><![CDATA[<p>La pagina de Yahoo developers tiene el API de Weather.com (que compro hace tiempo), Weather.com ya tenia un xml que ha simplificado Yahoo.com</p>
<p>Esta API nos permite obtener informacion del clima de practicamente cualquier lugar del mundo y sin duda es muy utilizada para varios widgets dentro de páginas o como widgets de escritorio.</p>
<p>Básicamente para usar esta API se hace una llamada a la siguiente dirección:<br />
<code>http://weather.yahooapis.com/forecastrss?p=CODIGO&#38;u=c</code></p>
<p>Donde código puede ser un Código Postal de Estados Unidos, o un ID de una ciudad en el mundo, el API de <a href="http://developer.yahoo.com/weather/" target="_blank">yahoo developers</a>, dice brevemente que para conseguir este ID se necesita ir a la página de Yahoo Weather y copiar de la URL el código de la ciudad.</p>
<p>Esto es realmente muy malo ya que lo que se busca es optimizar, pero ahi entra el API viejo de Weather.com, donde podemos enviarle una cadena con la ciudad a buscar y nos regresará diversos resultados que pueden concordar con el código de la ciudad y su nombre &#8220;legible&#8221;, la url es: <br />
<code>http://xoap.weather.com/weather/search/search?where=NOMBRE_CIUDAD</code></p>
<p>Por ejemplo para buscar la ciudad de Puebla, Mexico haremos:<br />
<a href="http://xoap.weather.com/weather/search/search?where=Puebla">http://xoap.weather.com/weather/search/search?where=Puebla</a></p>
<p>El resultado nos dará como resultado:</p>
<pre name="code" class="xml">&#60;!-- This document is intended only for use by authorized licensees of The  --&#62;
&#60;!-- Weather Channel. Unauthorized use is prohibited.  Copyright 1995-2008, --&#62;
&#60;!-- The Weather Channel Interactive, Inc.  All Rights Reserved.            --&#62;
&#60;search ver="2.0"&#62;
  &#60;loc id="MXPA0070" type="1"&#62;Puebla, Mexico&#60;/loc&#62;
&#60;/search&#62;</pre>
<p> </p>
<p>Que vemos que el elemento <code>loc</code> provee el ID de la ciudad y el nombre legible; ahora si podemos contruir la nueva URL que será:</p>
<p><a title="Clima de Puebla - RSS" href="http://weather.yahooapis.com/forecastrss?p=MXPA0070&#38;u=c" target="_blank">http://weather.yahooapis.com/forecastrss?p=MXPA0070&#38;u=c</a></p>
<p>El resultado es un documento RSS con un nombre de espacio (namespace) de <code>yweather</code>, la página contiene mucha información, mucha de ella redundante, pero lo que más nos importa es lo que tiene ese nombre de espacios como:</p>
<pre name="code" class="xml">&#60;yweather:condition  text="Partly Cloudy"  code="30"  temp="19"  date="Sat, 27 Sep 2008 5:49 pm CDT" /&#62;
&#60;yweather:location city="Puebla" region=""   country="MX"/&#62;
&#60;yweather:units temperature="C" distance="km" pressure="mb" speed="kph"/&#62;&#8230;</pre>]]></description>
			<content:encoded><![CDATA[<p>La pagina de Yahoo developers tiene el API de Weather.com (que compro hace tiempo), Weather.com ya tenia un xml que ha simplificado Yahoo.com</p>
<p>Esta API nos permite obtener informacion del clima de practicamente cualquier lugar del mundo y sin duda es muy utilizada para varios widgets dentro de páginas o como widgets de escritorio.</p>
<p>Básicamente para usar esta API se hace una llamada a la siguiente dirección:<br />
<code>http://weather.yahooapis.com/forecastrss?p=CODIGO&amp;u=c</code></p>
<p>Donde código puede ser un Código Postal de Estados Unidos, o un ID de una ciudad en el mundo, el API de <a href="http://developer.yahoo.com/weather/" target="_blank">yahoo developers</a>, dice brevemente que para conseguir este ID se necesita ir a la página de Yahoo Weather y copiar de la URL el código de la ciudad.</p>
<p>Esto es realmente muy malo ya que lo que se busca es optimizar, pero ahi entra el API viejo de Weather.com, donde podemos enviarle una cadena con la ciudad a buscar y nos regresará diversos resultados que pueden concordar con el código de la ciudad y su nombre &#8220;legible&#8221;, la url es: <br />
<code>http://xoap.weather.com/weather/search/search?where=NOMBRE_CIUDAD</code></p>
<p>Por ejemplo para buscar la ciudad de Puebla, Mexico haremos:<br />
<a href="http://xoap.weather.com/weather/search/search?where=Puebla">http://xoap.weather.com/weather/search/search?where=Puebla</a></p>
<p>El resultado nos dará como resultado:</p>
<pre name="code" class="xml">&lt;!-- This document is intended only for use by authorized licensees of The  --&gt;
&lt;!-- Weather Channel. Unauthorized use is prohibited.  Copyright 1995-2008, --&gt;
&lt;!-- The Weather Channel Interactive, Inc.  All Rights Reserved.            --&gt;
&lt;search ver="2.0"&gt;
  &lt;loc id="MXPA0070" type="1"&gt;Puebla, Mexico&lt;/loc&gt;
&lt;/search&gt;</pre>
<p> </p>
<p>Que vemos que el elemento <code>loc</code> provee el ID de la ciudad y el nombre legible; ahora si podemos contruir la nueva URL que será:</p>
<p><a title="Clima de Puebla - RSS" href="http://weather.yahooapis.com/forecastrss?p=MXPA0070&amp;u=c" target="_blank">http://weather.yahooapis.com/forecastrss?p=MXPA0070&amp;u=c</a></p>
<p>El resultado es un documento RSS con un nombre de espacio (namespace) de <code>yweather</code>, la página contiene mucha información, mucha de ella redundante, pero lo que más nos importa es lo que tiene ese nombre de espacios como:</p>
<pre name="code" class="xml">&lt;yweather:condition  text="Partly Cloudy"  code="30"  temp="19"  date="Sat, 27 Sep 2008 5:49 pm CDT" /&gt;
&lt;yweather:location city="Puebla" region=""   country="MX"/&gt;
&lt;yweather:units temperature="C" distance="km" pressure="mb" speed="kph"/&gt;
&lt;yweather:wind chill="19"   direction="150"   speed="11.27" /&gt;
&lt;yweather:atmosphere humidity="60"  visibility="1607.69"  pressure="0"  rising="0" /&gt;
&lt;yweather:astronomy sunrise="7:23 am"   sunset="7:24 pm"/&gt;</pre>
<p>El primero es lo más importante (<code>condition</code>), nos mostrará la información del clima, el código de estado (<code>code</code>), la temperatura (<code>temp</code>) y la fecha de cuando se obtuvo la información.<br />
El segundo (<code>location</code>) nos dice información del lugar.<br />
El tercero (<code>units</code>) nos dice en qué unidades está expresada la información, como hemos solicitado en formato de grados Centigrados el sistema muestra la información en sistema métrico.<br />
El cuarto (<code>wind</code>) nos da información del viento.<br />
El quinto (<code>atmosphere</code>) nos da información del medio ambiente en cuanto a humedad, visibilidad, etc<br />
El último (<code>astronomy</code>) nos da una breve información de cuando el sol aparece y se oculta en el horizonte.</p>
<p>La página también incluye una liga a la imagen del estado, yo he decidido utilizar las que provee <a href="http://www.weather.com" target="_blank">Weather.com</a></p>
<p>El nombre del estado no lo usaremos ya que está en inglés, por lo que hice una traducción del estado al nombre correspondiente, los códigos se pueden ver aqui:<br />
<a href="http://developer.yahoo.com/weather/#codes">http://developer.yahoo.com/weather/#codes</a></p>
<p> </p>
<p>Aqui tenemos un ejemplo ensamblado en PHP y Javascript:<br />
<a href="http://demo.livesourcing.com/blog_vida/articulos/DanguerArticle_Clima/">http://demo.livesourcing.com/blog_vida/articulos/DanguerArticle_Clima/</a></p>
<p> </p>
<p>Básicamente tiene tres partes, la primera nos permite introducir un nombre y obtener el ID de los lugares, obviamente está en ingles por lo que se tienen que hacer busquedas como &#8220;Mexico City&#8221; para encontrar la información del clima del D.F.</p>
<p>La segunda parte nos permite seleccionar de las distintas opciones de los lugares el que queramos ver su clima, después de seleccionarlo le damos click a &#8220;Obtener clima&#8221; y obtendremos el clima <img src='http://vida.danguer.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>El sistema muestra solamente el Estado (en español), la temperatura y la fecha con la imagen correspondiente del estado; en el ejemplo no obtuve información extra como información del viento o del medio ambiente, pero en base al ejemplo se puede extender fácilmente.</p>
<p> </p>
<p>Descargar el código fuente del ejemplo: <br />
<a href="http://demo.livesourcing.com/blog_vida/articulos/DanguerArticle_Clima.tar.gz" target="_blank">http://demo.livesourcing.com/blog_vida/articulos/DanguerArticle_Clima.tar.gz</a></p>
<p> </p>
<p><strong>Más información:</strong></p>
<ul>
<li>Sitio oficial de la API de Yahoo Weather:<br />
<a href="http://developer.yahoo.com/weather/" target="_blank">http://developer.yahoo.com/weather/</a></li>
<li>API &#8220;vieja&#8221; de Weather.com (son en si iguales pero tienen diferente forma de ser llamadas y obtener resultados):<br />
<a href="http://www.weather.com/services/xmloap.html">http://www.weather.com/services/xmloap.html</a> </li>
</ul>
<p> </p>
]]></content:encoded>
			<wfw:commentRss>http://vida.danguer.com/2008/09/27/ejemplo-de-api-de-yahoo-weather/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Actualización a Zend Framework 1.6</title>
		<link>http://vida.danguer.com/2008/09/05/actualizacion-a-zend-framework-16/</link>
		<comments>http://vida.danguer.com/2008/09/05/actualizacion-a-zend-framework-16/#comments</comments>
		<pubDate>Fri, 05 Sep 2008 08:03:40 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Trabajo]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://vida.danguer.com/?p=55</guid>
		<description><![CDATA[<p>Me acabo de dar cuenta que ya hay una nueva versión estable de Zend Framework, la 1.6.</p>
<p>Al parecer lo más novedoso es la incorporación de Dojo y la incorporación de SOAP. En lo particular no uso Dojo, pero vale la pena probar estos cambios.</p>
<p>No planeaba &#8220;actualizar&#8221; tan rápidamente, pero me acabo de dar cuenta que hay un bug en las versiones de 1.5.* que cuando Zend_Db lee un campo tipo LONGBLOB trata de reservar en una variable todo el tamaño máximo del longblob (aproximadamente 4GB) algo que hará tronar a PHP y marcará un fatal error.</p>
<p>Como estoy trabajando en un proyecto con LONGBLOB decidí actualizar, más adelante escribiré mis experiencias con los nuevos componentes, que SOAP es algo que tengo que probar =).</p>
<p><strong>Bug de Zend Framework</strong>:<a href="http://framework.zend.com/issues/browse/ZF-1498" target="_blank">http://framework.zend.com/issues/browse/ZF-1498</a></p>
<p><a title="Zend Framework - Version 1.6" href="http://framework.zend.com/download/latest" target="_blank">Descargar Zend Framework 1.6</a></p>
]]></description>
			<content:encoded><![CDATA[<p>Me acabo de dar cuenta que ya hay una nueva versión estable de Zend Framework, la 1.6.</p>
<p>Al parecer lo más novedoso es la incorporación de Dojo y la incorporación de SOAP. En lo particular no uso Dojo, pero vale la pena probar estos cambios.</p>
<p>No planeaba &#8220;actualizar&#8221; tan rápidamente, pero me acabo de dar cuenta que hay un bug en las versiones de 1.5.* que cuando Zend_Db lee un campo tipo LONGBLOB trata de reservar en una variable todo el tamaño máximo del longblob (aproximadamente 4GB) algo que hará tronar a PHP y marcará un fatal error.</p>
<p>Como estoy trabajando en un proyecto con LONGBLOB decidí actualizar, más adelante escribiré mis experiencias con los nuevos componentes, que SOAP es algo que tengo que probar =).</p>
<p><strong>Bug de Zend Framework</strong>:<a href="http://framework.zend.com/issues/browse/ZF-1498" target="_blank">http://framework.zend.com/issues/browse/ZF-1498</a></p>
<p><a title="Zend Framework - Version 1.6" href="http://framework.zend.com/download/latest" target="_blank">Descargar Zend Framework 1.6</a></p>
]]></content:encoded>
			<wfw:commentRss>http://vida.danguer.com/2008/09/05/actualizacion-a-zend-framework-16/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MVC en Zend Framework</title>
		<link>http://vida.danguer.com/2008/09/01/mvc-en-zend-framework/</link>
		<comments>http://vida.danguer.com/2008/09/01/mvc-en-zend-framework/#comments</comments>
		<pubDate>Mon, 01 Sep 2008 09:12:29 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://vida.danguer.com/?p=50</guid>
		<description><![CDATA[<p><a title="MVC - Modelo-Vista-Controlador Wikipedia" href="http://es.wikipedia.org/wiki/Modelo_Vista_Controlador" target="_blank">MVC</a> es un acrónimo para Model-View-Controller (Modelo-Vista-Controlador); esta es un patrón de arquitectura de software.</p>
<p>Básicamente este patrón divide una aplicación (en nuestro caso una aplicación web) en tres partes:</p>
<ul>
<li><strong>Modelo</strong><br />
Es la parte que se entenderá con la base de datos, una manera elegante y clara de separar esto, es que para cada tabla generar una clase que será su Modelo, aunque en realidad podría ser que un Modelo controle varias tablas que tengan mucho en común, por ejemplo para las relaciones muchos-a-muchos.</li>
<li><strong>Controlador</strong><br />
Se encarga de procesar la entrada del usuario, en nuestro caso de recoger los datos de formularios, la URL, etc. Procesarlos (utilizando los otros componentes ya que esta parte debería ser la única que se comunica con los demás y las otras partes deben estar aisladas) y producir un resultado.</li>
<li><strong>Vista</strong><br />
Es la parte que maneja la parte que el usuario verá, el caso más común es tener una página en HTML, pero las posibilidades son que podemos tener incluso páginas en WAP (contenido móbil) o representaciones de texto. El controlador procesará todo lo necesario y enviará sus resultados a la vista (en el caso de Zend Framework mediante asignación de variables). La vista procesará todos los datos de una manera que sean claros para el usuario (aunque una vez más, esto podría ser incluso tener como salida por ejemplo XML para una API para comunicación entre librerías)</li>
</ul>
<p>En este tutorial veremos de manera introductoria como funciona el patrón de MVC con Zend Framework. Antes de ver el código, mostraremos como funciona básicamente Zend Framework con MVC mediante el siguiente esquema:</p>
<p><img src="http://vida.danguer.com/archivos/articulos/Zend_MVC/MVC_Proceso.png" alt="Proceso de MVC en Zend Framework" width="530" height="510" /></p>
<p>En el esquema el primer paso es cuando accedemos a una dirección, por ejemplo <code>http://www.danguer.com/ajax/resultado</code></p>
<p>La configuración de Zend Framework mediante Apache utilizando <a title="Mod-Rewrite Apache Ingles" href="http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html" target="_blank">Mod_Rewrite</a> hace que la mayoría de ligas (con algunas excepciones por ejemplo extensiones de hojas de estilo, javascript, etc) las procese el archivo&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p><a title="MVC - Modelo-Vista-Controlador Wikipedia" href="http://es.wikipedia.org/wiki/Modelo_Vista_Controlador" target="_blank">MVC</a> es un acrónimo para Model-View-Controller (Modelo-Vista-Controlador); esta es un patrón de arquitectura de software.</p>
<p>Básicamente este patrón divide una aplicación (en nuestro caso una aplicación web) en tres partes:</p>
<ul>
<li><strong>Modelo</strong><br />
Es la parte que se entenderá con la base de datos, una manera elegante y clara de separar esto, es que para cada tabla generar una clase que será su Modelo, aunque en realidad podría ser que un Modelo controle varias tablas que tengan mucho en común, por ejemplo para las relaciones muchos-a-muchos.</li>
<li><strong>Controlador</strong><br />
Se encarga de procesar la entrada del usuario, en nuestro caso de recoger los datos de formularios, la URL, etc. Procesarlos (utilizando los otros componentes ya que esta parte debería ser la única que se comunica con los demás y las otras partes deben estar aisladas) y producir un resultado.</li>
<li><strong>Vista</strong><br />
Es la parte que maneja la parte que el usuario verá, el caso más común es tener una página en HTML, pero las posibilidades son que podemos tener incluso páginas en WAP (contenido móbil) o representaciones de texto. El controlador procesará todo lo necesario y enviará sus resultados a la vista (en el caso de Zend Framework mediante asignación de variables). La vista procesará todos los datos de una manera que sean claros para el usuario (aunque una vez más, esto podría ser incluso tener como salida por ejemplo XML para una API para comunicación entre librerías)</li>
</ul>
<p>En este tutorial veremos de manera introductoria como funciona el patrón de MVC con Zend Framework. Antes de ver el código, mostraremos como funciona básicamente Zend Framework con MVC mediante el siguiente esquema:</p>
<p><img src="http://vida.danguer.com/archivos/articulos/Zend_MVC/MVC_Proceso.png" alt="Proceso de MVC en Zend Framework" width="530" height="510" /></p>
<p>En el esquema el primer paso es cuando accedemos a una dirección, por ejemplo <code>http://www.danguer.com/ajax/resultado</code></p>
<p>La configuración de Zend Framework mediante Apache utilizando <a title="Mod-Rewrite Apache Ingles" href="http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html" target="_blank">Mod_Rewrite</a> hace que la mayoría de ligas (con algunas excepciones por ejemplo extensiones de hojas de estilo, javascript, etc) las procese el archivo index.php que contiene el código básico para inicializar el MVC que veremos más adelante.</p>
<p>Este archivo <code>index.php</code> tiene un código básico para inicializar toda la aplicación web, lo cual es ya de entrada interesante. Para la estructura de directorios será de la siguiente manera:</p>
<p><img src="http://vida.danguer.com/archivos/articulos/Zend_MVC/MVC_Estructura.png" alt="Estructura de Directorios de Zend Framework MVC" width="261" height="197" /></p>
<p>Tendremos la carpeta principal <code>app/</code> que será donde irá todo el código de PHP, dentro de esta carpeta tenemos varias carpetas pero las principales son:</p>
<ul>
<li><code>controllers</code>, donde estará el código de los controladores</li>
<li><code>models</code>, donde estará el código de los modelos (no lo utilizaremos)</li>
<li><code>layout</code>, las plantillas para el sitio (parte de las vistas)</li>
<li><code>views</code>, las vistas junto con &#8220;ayudantes&#8221; (<code>helpers</code>)</li>
</ul>
<p>La carpeta adicional <code>langs</code>, es una carpeta opcional y personal que he dejado del ejemplo de tutorial con <code>Zend_Form</code>, solo para ilustrar que se pueden crear carpetas adicionales sin problemas.</p>
<p>Como nota personal a mi me gusta dejar código que es necesario dentro de la carpeta <code>/app</code>, en el ejemplo se puede ver el archivo: <code>Danguer_Controller_Action.php</code> que después veremos a detalle. Esto es totalmente preferencia personal de como estructurar el archivo.</p>
<p>Después de la carpeta <code>/app</code>, hay una carpeta <code>styles/</code> que contiene archivos CSS, en realidad la carpeta no será visible para el usuario ya que <code>http://sitio/styles</code> intentará interpretarlo como código PHP mediante controladores como veremos más adelante.</p>
<p>Hay sugerencias de seguridad de como estructurar estas carpetas, pero en lo personal para mis desarrollos utilizo la estructura mostrada para no separar por completo el código y tenerlo todo en un solo lugar.</p>
<p>El archivo realmente importante es <code>index.php</code> y por supuesto <code>.htaccess</code>, el primero tiene el código de manejo para el MVC de Zend Framework y el segundo es un archivo para que Apache redireccione todas las peticiones al archivo <code>index.php</code></p>
<p><strong>Contenido del archivo <code>index.php</code> y <code>.htaccess</code></strong></p>
<p>El archivo .htaccess es muy simple, debido a que solamente habilita <code>Mod_Rewrite</code> y redirecciona todas las peticiones al archivo index.php:</p>
<pre name="code" class="php">RewriteEngine on

RewriteRule !\.(js|ico|gif|jpg|png|css|swf)$ index.php
</pre>
<p>La primera linea habilita <code>Mod_Rewrite</code>, la otra linea indica que salvo las ligas que contengan las extensiones <code>js</code>, <code>ico</code>, <code>gif</code>, <code>jpg</code>, <code>png</code>, <code>css</code> y <code>swf</code> deben procesarse con el archivo <code>index.php</code>, aqui se puede hacer que por ejemplo se habiliten algunos directorios para no ser procesador por el archivo <code>index.php</code> (por ejemplo un directorio de imagenes), pero esto debe ser tratado con cada caso en particular.</p>
<p>El archivo index.php contiene más lineas, pero son muy sencillas:</p>
<pre name="code" class="php">require_once 'Zend/Controller/Front.php';
require_once 'Zend/Layout.php';

require_once './app/Danguer_Controller_Action.php';

// Configurar controlador
$controller = Zend_Controller_Front::getInstance();
$controller-&gt;setControllerDirectory('./app/controllers');
$controller-&gt;throwExceptions(true); 

// asignar MVC
Zend_Layout::startMvc(array(
    'layoutPath' =&gt; './app/layouts',
    'layout' =&gt; 'principal'
	));

// ejecutar!
$controller-&gt;dispatch();
</pre>
<p>Las primeras lineas llaman las librerías necesarias que son el &#8220;despachador&#8221; de los controladores (<code>Zend/Controller/Front.php</code>) y la plantilla (<code>Zend/Layout.php</code>) la otra línea requiriendo un archivo en php (<code>./app/Danguer_Controller_Action.php</code>) será discutido más adelante, pero en esta parte podemos incluir todas los archivos/librerías que necesitemos, tanto de Zend como propios.</p>
<p>La siguiente línea de código genera el despachador, básicamente genera una instancia de este despachador (es única para toda la aplicación, por eso utilizamos de manera estática sin construirlo), asignamos el directorio de los controladores (<code>./app/controllers</code>) y por último permitimos que muestre excepciones por ser código en desarrollo (en producción se sugiere no utilizarlo para no dejar ver código importante a los usuarios).</p>
<p>La siguiente parte tiene como misión inicializar el sistema MVC de la parte de la plantilla. Anteriormente Zend Framework no manejaba plantillas en sus vistas, algo odioso porque se necesitaba crear un código propio (aunque había buenos ejemplos en la red). Actualmente con esa línea podemos definir la plantilla que utilizarán las vistas. Más adelante veremos como está hecha la plantilla.<br />
Con ese código hemos definido que el sistema debe buscar en el directorio <code>./app/layouts</code> las plantillas, y que la plantilla por defecto es &#8216;principal&#8217; que el archivo debe llamarse: <code>./app/layouts/principal.phtml</code></p>
<p>Con esto el sistema llamará a los controladores de la manera que veremos en la siguiente sección.</p>
<p><strong>Proceso del MVC</strong></p>
<p>Zend Framework una vez que tenga la liga (en este caso <code>/ajax/resultado</code>) procederá a &#8220;enrutarla&#8221;, es decir a convertir la liga en el controlador y acción deseada. Si no modificamos nada, por defecto el enrutamiento funciona de la siguiente manera:</p>
<pre name="code" class="php">http://sitio/controlador/accion
</pre>
<p>Así en nuestro ejemplo, el controlador es &#8220;<code>ajax</code>&#8221; y la acción es &#8220;<code>resultado</code>&#8220;. Por supuesto se pueden definir rutas alternativas, por ejemplo se puede decir que <code>http://sitio/blog/2008</code> sea el controlador &#8220;<code>blog</code>&#8220;, la acción &#8220;<code>archivos</code>&#8221; y pasarle a la acción un parámetro de nombre &#8220;<code>annio</code>&#8221; con el valor <code>2008</code>. Esto podría ser un alias de: <code>http://sitio/blog/archivos?annio=2008</code> que funciona bajo la configuración estándar</p>
<p>El ruteador puede ser tan personalizado que podemos pasar nuestro propio ruteador siempre y cuando se extienda de la interfaz: <code>Zend_Controller_Router_Interface</code>, o en su defecto que extienda la clase <code>Zend_Controller_Router_Abstract</code>, pero esto son temas avanzados que podemos discutir en otro tutorial =).</p>
<p>Una vez que el sistema sabe que controlador y acción es, procederá a llamar al controlador y a la acción. El controlador debe ser especificado de la siguiente forma:</p>
<pre name="code" class="php">&lt;?php
require_once 'Zend/Controller/Action.php';

class ControladorController extends Zend_Controller_Action {
    public function accionAction() {
         //codigo del controlador
    }
}
</pre>
<p>En donde el nombre de la clase debe ser el nombre del controlador iniciando con mayúscula y seguido por &#8216;<code>Controller</code>&#8216; (sin espacios) y cada nombre de función debe ser el nombre de la acción seguido por &#8216;<code>Action</code>&#8216; (sin espacios). El nombre del archivo debe ser igual que el nombre de la clase y se almacena dentro de la carpeta <code>/app/controllers</code>.</p>
<p>En el caso anterior para la liga <code>/ajax/resultado</code> nuestro archivo sería el siguiente:</p>
<pre name="code" class="php">&lt;?php
require_once 'Zend/Controller/Action.php';

class AjaxController extends Zend_Controller_Action {
    public function resultadoAction() {
         //codigo del controlador
    }
}
</pre>
<p>Cuando entremos a la liga mencionada, el sistema procesará todo el código en la función de la acción. Como vemos nuestra clase extiende de <code>Zend_Controller_Action</code>, esta clase contendrá básicamente:</p>
<ul>
<li>una petición (que contiene información de variables de entrada o del sistema)</li>
<li>una respuesta (que puede ser para redireccionar la página a otra por ejemplo)</li>
<li>la vista</li>
</ul>
<p>Por defecto el sistema crea una vista, crea las variables de la petición y la respuesta, llama a la función de la acción; y por último llama a un &#8220;ayudante&#8221; para que la vista sea generada y la salida se envia al navegador. Es por esto que dentro del controlador no llamaremos a la función <code>render</code> ya que la clase principal lo hace automáticamente.</p>
<p>Para obtener información de entrada, como un parámetro que se especificó mediante <code>/controlador/accion?variable=valor</code> utilizamos la variable de la petición de la siguiente manera:</p>
<pre name="code" class="php">$peticion = $this-&gt;getRequest();
$valor = $peticion-&gt;getParam('variable');
</pre>
<p>También existe una función <code>$peticion-&gt;getParams();</code> que regresa un arreglo asociativo con todas las variables y sus valores.</p>
<p>Para pasar una variable a la vista existe una variable <code>$this-&gt;view</code> dentro del controlador a la que podemos pasar valores de la siguiente forma:</p>
<pre name="code" class="php">$variable = 'Hola mundo';
$this-&gt;view-&gt;assign('variable', $variable);
//la vista ahora tendrá una variable que puede ser accesada como $this-&gt;variable
</pre>
<p>Más adelante veremos algunas opciones útiles para inicializar valores en la vista o cambiar el ciclo de renderizado de la vista.</p>
<p><strong>Vistas</strong></p>
<p>Las vistas deben ser guardadas en el directorio <code>apps/views/scripts/controlador/</code> con el nombre de archivo: <code>accion.phtml</code>, así por ejemplo para nuestro ejemplo de /ajax/resultado debemos crear el siguiente archivo: <code>apps/views/scripts/ajax/resultado.phtml</code></p>
<p>La vista contendrá archivo principalmente HTML, pero podemos procesar código PHP de forma normal entre <code>&lt;?php</code> y <code>?&gt;</code>, Zend también permite que las vistas utilicen cualquier otro sistema de plantillas que esté escrito en PHP, por ejemplo <a title="Proyecto de Smarty" href="http://www.smarty.net/" target="_blank">Smarty</a>.</p>
<p>Dentro llamamos a las variables que hemos asignado de la siguiente manera:</p>
<pre name="code" class="php">&lt;?=$this-&gt;variable?&gt;
</pre>
<p>Dentro de las vistas podemos alterar un poco la plantilla, para iniciar podemos cambiar el título de la siguiente manera:</p>
<pre name="code" class="php">&lt;?php
$this-&gt;headTitle('Ventana emergente');
?&gt;
</pre>
<p>Eso hará que el título de la página sea &#8220;Ventana Emergente&#8221;, pero también podemos agregar un archivo de hoja de estilo de la siguiente manera:</p>
<pre name="code" class="php">&lt;?php
$this-&gt;headLink()-&gt;appendStylesheet($this-&gt;baseUrl.'/styles/archivo.css', 'screen');
?&gt;
</pre>
<p>O incluir un archivo de javascript:</p>
<pre name="code" class="php">&lt;?php
$this-&gt;headScript()-&gt;appendFile($this-&gt;baseUrl.'/scripts/archivo.js');
?&gt;
</pre>
<p>El sistema de plantillas tiene algunas opciones extra que por brevedad no revisaremos, pero incluyen la posibilidad de incluir código en javascript/css que manejará de manera adecuada mediante una cadena.</p>
<p>La variable de <code>$this-&gt;baseUrl</code>, no es estándar de las vistas y es algo que yo he agregado y que veremos más adelante como se logra.</p>
<p><strong>Plantillas</strong></p>
<p>Las plantillas son muy simples, tienen el siguiente modelo:</p>
<pre name="code" class="php">&lt;?php
/* con esto establecemos un documento XHTML */
echo '&lt;?xml version="1.0" encoding="UTF-8" ?&gt;';
/* esto generará las cabeceras de XHTML,
   también podemos definir otras como HTML 4 */
echo $this-&gt;doctype()
?&gt;

&lt;html&gt;

	&lt;head&gt;
		&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;
		&lt;!-- es bueno definir algunas etiquetas "globales" aunque pueden hacerse sobreescribiendo el Danguer_Action_Controller  --&gt;
		&lt;link type="text/css" href="&lt;?=$this-&gt;baseUrl?&gt;/styles/main.css" rel="stylesheet" /&gt;		

		&lt;?php
			/* Con esto nos aseguramos que el título siempre tenga un nombre al inicio */
			$this-&gt;headTitle('Ejemplo de MVC, danguer.com | ',Zend_View_Helper_Placeholder_Container_Abstract::PREPEND);

			echo $this-&gt;headTitle();
		    echo $this-&gt;headScript();
		    echo $this-&gt;headStyle();
	    ?&gt;
	&lt;/head&gt;

	&lt;body&gt;
		&lt;!--  solo contenido, esto puede ser usado para un popup --&gt;
		&lt;?php echo $this-&gt;layout()-&gt;content ?&gt;
	&lt;/body&gt;

&lt;/html&gt;
</pre>
<p>Como vemos definimos básicamente la plantilla del documento y definimos una parte que será donde irá el contenido con: <code>&lt;?php echo $this-&gt;layout()-&gt;content ?&gt;</code>, esta parte es reemplazada por la vista en cuestión.<br />
La otra parte dinámica es:</p>
<pre name="code" class="php">&lt;?php
			/* Con esto nos aseguramos que el título siempre tenga un nombre al inicio */
			$this-&gt;headTitle('Ejemplo de MVC, danguer.com | ',Zend_View_Helper_Placeholder_Container_Abstract::PREPEND);

			echo $this-&gt;headTitle();
		    echo $this-&gt;headScript();
		    echo $this-&gt;headStyle();
	    ?&gt;
</pre>
<p>Que se reemplazará como vimos anteriormente por el título de la página, los archivos de scripts y las hojas de estilo.</p>
<p>Una plantilla también puede tener zonas de contenido, donde desde la vista podemos llenarlas, por ejemplo podemos tener una zona que indique un mensaje y no tendremos que alterar la plantilla segmentándola en diferentes archivos como se suele hacer. Eso se verá en otro tutorial =)</p>
<p><strong>Controlador Base</strong></p>
<p>En lo particular me gusta crear un controlador base que contiene código de utilidad para mis aplicaciones, casi siempre utilizo uno. En el código de ejemplo tiene nombre: <code>app/Danguer_Controller_Action.php</code></p>
<p>Lo que hace este controlador base es lo siguiente:</p>
<ul>
<li>Asigna variables a la vista (por ejemplo <code>baseUrl</code> que es el directorio base de ligas relativas, muy útil para subdirectorios)</li>
<li>Permite deshabilitar el renderizado automático (ya que al finalizar la función intentará buscar el archivo de vista que puede no existir por ejemplo para resultados de <code>AJAX</code>)</li>
<li>Tiene funciones de utilidad, en el ejemplo tiene una función para enviar datos en formato <code>JSON </code>con el simple llamado de una función, pero puede incluir código que se compartan entre todos (o la mayoría) de controladores</li>
</ul>
<p>El código del controlador base es el siguiente:</p>
<pre name="code" class="php">&lt;?php
require_once 'Zend/Controller/Action.php';

class Danguer_Controller_Action extends Zend_Controller_Action {
	protected $autoRender = true;

    public function initView()
    {
    	parent::initView();

	    $this-&gt;view-&gt;assign('baseUrl', $this-&gt;getRequest()-&gt;getBaseUrl());
		$this-&gt;view-&gt;assign('fullUrl', $this-&gt;getFullURL());
    	return $this-&gt;view;
    }

    public function init() {
    	$this-&gt;initView();
    }

    public function disableAutoRender() {
    	$this-&gt;autoRender = false;
    	$args = $this-&gt;getInvokeArgs();   	

    	$args['noViewRenderer'] = true;
    	$this-&gt;_setInvokeArgs($args);

    	$this-&gt;_helper-&gt;resetHelpers();
    }

    protected function getFullURL() {
    	$protocol = 'http://';
    	$host = $_SERVER['HTTP_HOST'];
    	$port = $_SERVER['SERVER_PORT'];

    	if ($port != '80')
    		$port = ":{$port}";
    	else
   			$port = '';

    	return "{$protocol}{$host}{$port}".$this-&gt;getRequest()-&gt;getBaseUrl();
    }

	protected function writeJSON($data) {
		require_once 'Zend/Json.php';

		$this-&gt;disableAutoRender();
		header('Content-Type: text/javascript');

		print Zend_Json::encode($data);
	}
}
</pre>
<p>La función init (similar al constructor de clases) forza a iniciar la vista, en esa función (initView) se llama al padre para que genere el objeto de vista y le asignemos variables predefinidas. Aqui podemos incluir todas las variables que necesitemos.</p>
<p>Las otras dos funciones extras son:</p>
<ul>
<li><code>disableAutoRender</code><br />
Permite deshabilitar el auto-renderizado para que la aplicación no busque el archivo de la acción.</li>
<li><code>writeJSON</code><br />
Codifica una variable en formato JSON (apropiado para AJAX), también automáticamente deshabilita el auto-renderizado</li>
</ul>
<p>Estas funciones son ejemplo de lo que se puede lograr personalizando el sistema MVC.</p>
<p>Por último si se necesita modificar la plantilla, es muy sencillo; en el código del controlador simplemente necesitamos hacer los siguientes pasos:</p>
<pre name="code" class="php">$mvc = Zend_Layout::getMvcInstance();
$mvc-&gt;setLayout('simple'); //utilizar la plantilla app/layouts/simple.phtml
</pre>
<p>Esto es la base para entender el modelo MVC de Zend Framework, más adelante explicaré más a detalle cosas como los ayudantes, modelos y Ruteadores.</p>
<p>Código fuente: <a title="Ejemplo de Zend Framework MVC" href="http://vida.danguer.com/archivos/articulos/Zend_MVC/DanguerArticle_Zend_MVC.tar.gz" target="_self">DanguerArticle_Zend_MVC.tar.gz</a></p>
<p><a title="Sitio Demo Zend Framework MVC" href="http://demo.livesourcing.com/blog_vida/articulos/DanguerArticle_Zend_MVC" target="_blank">Ver sitio demo</a></p>
]]></content:encoded>
			<wfw:commentRss>http://vida.danguer.com/2008/09/01/mvc-en-zend-framework/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
	</channel>
</rss>
