Skip to content

Commit

Permalink
Merge pull request #28 from wilsenhc/ch-08-databases
Browse files Browse the repository at this point in the history
Capítulo 8: Bases de Datos
  • Loading branch information
wilsenhc authored Oct 10, 2024
2 parents 676ac40 + 93cea06 commit 6250d28
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 70 deletions.
12 changes: 6 additions & 6 deletions _posts/07-01-01-Databases.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ anchor: bases_de_datos

# Bases de Datos {#bases_de_datos_title}

Many times your PHP code will use a database to persist information. You have a few options to connect and interact
with your database. The recommended option **until PHP 5.1.0** was to use native drivers such as [mysqli], [pgsql],
[mssql], etc.
Muchas veces su código PHP utilizará una base de datos para persistir información. Tiene algunas opciones para conectarse
e interactuar con su base de datos. La opción recomendada **hasta PHP 5.1.0** era usar controladores nativos como [mysqli],
[pgsql], [mssql], etc.

Native drivers are great if you are only using _one_ database in your application, but if, for example, you are using
MySQL and a little bit of MSSQL, or you need to connect to an Oracle database, then you will not be able to use the
same drivers. You'll need to learn a brand new API for each database — and that can get silly.
Los drivers nativos son geniales si sólo estás usando _una_ base de datos en tu aplicación, pero si, por ejemplo, estás usando MySQL
y un poco de MSSQL, o necesitas conectarte a una base de datos Oracle, entonces no podrás usar los mismos drivers.
Tendrás que aprender una API completamente nueva para cada base de datos — y eso puede llegar a ser una tontería.


[mysqli]: https://www.php.net/mysqli
Expand Down
23 changes: 11 additions & 12 deletions _posts/07-02-01-Databases_MySQL.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,25 @@ anchor: extension_mysql

## Extensión MySQL {#extension_mysql_title}

The [mysql] extension for PHP is incredibly old and has been superseded by two other extensions:
La extensión [mysql] para PHP es increíblemente antigua y ha sido reemplazada por otras dos extensiones:

- [mysqli]
- [pdo]

Not only did development stop long ago on [mysql], but it
**has been [officially removed in PHP 7.0][mysql_removed]**.
No sólo el desarrollo de [mysql] se detuvo hace mucho tiempo, sino que además
**ha sido [oficialmente eliminado en PHP 7.0][mysql_removed]**.

To save digging into your `php.ini` settings to see which module you are using, one option is to search for `mysql_*`
in your editor of choice. If any functions such as `mysql_connect()` and `mysql_query()` show up, then `mysql` is
in use.
Para ahorrarse la búsqueda en su `php.ini` para ver qué módulo está utilizando, una opción es buscar `mysql_*`
en el editor de su elección. Si aparecen funciones como `mysql_connect()` y `mysql_query()`, entonces está usando `mysql`.

Even if you are not using PHP 7.x or later yet, failing to consider this upgrade as soon as possible will lead to greater
hardship when the PHP upgrade does come about. The best option is to replace mysql usage with [mysqli] or [PDO] in
your applications within your own development schedules so you won't be rushed later on.
Incluso si aún no está utilizando PHP 7.x o posterior, no considerar esta actualización lo antes posible le acarreará mayores
dificultades cuando se produzca la actualización de PHP. La mejor opción es reemplazar el uso de mysql por [mysqli] o [PDO] en tus
aplicaciones dentro de tus propios calendarios de desarrollo para que no te veas apurado más adelante.

**If you are upgrading from [mysql] to [mysqli], beware lazy upgrade guides that suggest you can simply find and replace `mysql_*` with `mysqli_*`. Not only is that a gross oversimplification, it misses out on the advantages that mysqli provides, such as parameter binding, which is also offered in [PDO][pdo].**
**Si está actualizando de [mysql] a [mysqli], tenga cuidado con las guías de actualización perezosas que sugieren que simplemente puede encontrar y reemplazar `mysql_*` con `mysqli_*`. No sólo es una simplificación excesiva, sino que pierde las ventajas que mysqli proporciona, como la vinculación de parámetros, que también se ofrece en [PDO][pdo].**

* [MySQLi Prepared Statements][mysqli_prepared_statements]
* [PHP: Choosing an API for MySQL][mysql_api]
* [Sentencias Preparadas de MySQLi][mysqli_prepared_statements]
* [PHP: Cómo elegir una API para MySQL][mysql_api]

[mysql]: https://www.php.net/mysqli
[mysql_removed]: https://www.php.net/manual/migration70.removed-exts-sapis.php
Expand Down
52 changes: 26 additions & 26 deletions _posts/07-03-01-Databases_PDO.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ anchor: extension_pdo

## Extensión PDO {#extension_pdo_title}

[PDO] is a database connection abstraction library — built into PHP since 5.1.0 — that provides a common
interface to talk with many different databases. For example, you can use basically identical code to interface with
MySQL or SQLite:
[PDO] es una librería de abstracción de conexión a bases de datos — incorporada en PHP desde 5.1.0 — que proporciona
una interfaz común común para hablar con muchas bases de datos diferentes. Por ejemplo, puede utilizar código básicamente idéntico
para interactuar con MySQL o SQLite:

{% highlight php %}
<?php
Expand All @@ -25,50 +25,50 @@ $row = $statement->fetch(PDO::FETCH_ASSOC);
echo htmlentities($row['some_field']);
{% endhighlight %}

PDO will not translate your SQL queries or emulate missing features; it is purely for connecting to multiple types of
database with the same API.
PDO no traducirá sus consultas SQL o emulará las características que faltan; es puramente para la conexión a múltiples tipos
de base de datos con la misma API.

More importantly, `PDO` allows you to safely inject foreign input (e.g. IDs) into your SQL queries without worrying
about database SQL injection attacks.
This is possible using PDO statements and bound parameters.
Y lo que es más importante, `PDO` le permite inyectar de forma segura entradas ajenas (por ejemplo, IDs) en sus consultas SQL sin preocuparse
por ataques de inyección SQL a bases de datos.
Esto es posible utilizando sentencias PDO y parámetros vinculados.

Let's assume a PHP script receives a numeric ID as a query parameter. This ID should be used to fetch a user record
from a database. This is the `wrong` way to do this:
Supongamos que un script PHP recibe un ID numérico como parámetro de consulta. Este ID debe ser usado para obtener un registro
de usuario de una base de datos. Esta es la forma `incorrecta` de hacer esto:

{% highlight php %}
<?php
$pdo = new PDO('sqlite:/path/db/users.db');
$pdo->query("SELECT name FROM users WHERE id = " . $_GET['id']); // <-- NO!
{% endhighlight %}

This is terrible code. You are inserting a raw query parameter into a SQL query. This will get you hacked in a
heartbeat, using a practice called [SQL Injection]. Just imagine if a hacker passes in an inventive `id` parameter by
calling a URL like `http://domain.com/?id=1%3BDELETE+FROM+users`. This will set the `$_GET['id']` variable to `1;DELETE
FROM users` which will delete all of your users! Instead, you should sanitize the ID input using PDO bound parameters.
Este código es terrible. Estás insertando un parámetro de consulta sin procesar en una consulta SQL. Esto hará que te hackeen en un santiamén, usando una práctica llamada [Inyección SQL][SQL Injection]. Imagínese si un hacker pasa un parámetro `id` inventivo
llamando a una URL como `http://domain.com/?id=1%3BDELETE+FROM+users`. Esto establecerá la variable `$_GET['id']` a
`1;DELETE FROM users` lo que borrará todos los usuarios. En su lugar, debería desinfectar/sanitizar la entrada de ID utilizando
parámetros vinculados a PDO.

{% highlight php %}
<?php
$pdo = new PDO('sqlite:/path/db/users.db');
$stmt = $pdo->prepare('SELECT name FROM users WHERE id = :id');
$id = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT); // <-- filter your data first (see [Data Filtering](#data_filtering)), especially important for INSERT, UPDATE, etc.
$stmt->bindParam(':id', $id, PDO::PARAM_INT); // <-- Automatically sanitized for SQL by PDO
$id = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT); // <-- filtre primero los datos (ver [Filtrado de Datos](#filtrado_de_datos)), especialmente importante para INSERT, UPDATE, etc.
$stmt->bindParam(':id', $id, PDO::PARAM_INT); // <-- SQL saneado automáticamente por PDO
$stmt->execute();
{% endhighlight %}

This is correct code. It uses a bound parameter on a PDO statement. This escapes the foreign input ID before it is
introduced to the database preventing potential SQL injection attacks.
Este código es correcto. Utiliza un parámetro vinculado en una sentencia PDO. Esto escapa el ID de entrada externo
antes de que sea introducido en la base de datos previniendo potenciales ataques de inyección SQL.

For writes, such as INSERT or UPDATE, it's especially critical to still [filter your data](#data_filtering) first and sanitize it for other things (removal of HTML tags, JavaScript, etc). PDO will only sanitize it for SQL, not for your application.
Para escrituras, como INSERT o UPDATE, es especialmente crítico [filtrar sus datos](#filtrado_de_datos) primero y sanearlos para otras cosas (eliminación de etiquetas HTML, JavaScript, etc). PDO sólo lo desinfectará para SQL, no para su aplicación.

* [Learn about PDO][pdo]
* [Más información sobre PDO][pdo]

You should also be aware that database connections use up resources and it was not unheard-of to have resources
exhausted if connections were not implicitly closed, however this was more common in other languages. Using PDO you can
implicitly close the connection by destroying the object by ensuring all remaining references to it are deleted, i.e.
set to NULL. If you don't do this explicitly, PHP will automatically close the connection when your script ends -
unless of course you are using persistent connections.
También hay que tener en cuenta que las conexiones a bases de datos consumen recursos y no era raro que se agotaran los recursos
si las conexiones no se cerraban implícitamente, aunque esto era más común en otros lenguajes. Usando PDO puedes cerrar implícitamente
la conexión destruyendo el objeto asegurándote de que todas las referencias restantes a él son borradas, es decir, establecidas a NULL.
Si no hace esto explícitamente, PHP cerrará automáticamente la conexión cuando su script termine -
a menos que esté usando conexiones persistentes.

* [Learn about PDO connections]
* [Más información sobre las conexiones PDO][Learn about PDO connections]


[pdo]: https://www.php.net/pdo
Expand Down
35 changes: 17 additions & 18 deletions _posts/07-04-01-Interacting-via-Code.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ anchor: interaccion_con_bases_de_datos

## Interacción con Bases de Datos {#interaccion_con_bases_de_datos_title}

When developers first start to learn PHP, they often end up mixing their database interaction up with their
presentation logic, using code that might look like this:
Cuando los desarrolladores comienzan a aprender PHP, a menudo terminan mezclando su interacción con la base de datos con su
lógica de presentación, utilizando código que podría parecerse a esto:

{% highlight php %}
<ul>
Expand All @@ -19,13 +19,12 @@ foreach ($db->query('SELECT * FROM table') as $row) {
</ul>
{% endhighlight %}

This is bad practice for all sorts of reasons, mainly that it's hard to debug, hard to test, hard to read and it is
going to output a lot of fields if you don't put a limit on there.
Esta es una mala práctica por todo tipo de razones, principalmente que es difícil de depurar, difícil de probar, difícil de leer
y que va a dar salida a un montón de campos si no pones un límite.

While there are many other solutions to doing this - depending on if you prefer [OOP](/#object-oriented-programming) or
[functional programming](/#functional-programming) - there must be some element of separation.
Aunque hay muchas otras soluciones para hacer esto - dependiendo de si prefieres [POO](/#programación-orientada-a-objetos) o [programación funcional](/#programación-funcional) - debe haber algún elemento de separación.

Consider the most basic step:
Considere el paso más básico:

{% highlight php %}
<?php
Expand All @@ -39,27 +38,27 @@ foreach ($results as $row) {
}
{% endhighlight %}

That is a good start. Put those two items in two different files and you've got some clean separation.
Es un buen comienzo. Pon esos dos elementos en dos archivos diferentes y tendrás una separación limpia.

Create a class to place that method in and you have a "Model". Create a simple `.php` file to put the presentation
logic in and you have a "View", which is very nearly [MVC] - a common OOP architecture for most
[frameworks](/#frameworks).
Crea una clase en la que colocar ese método y tendrás un "Modelo". Crea un simple archivo `.php` para colocar
la lógica de presentación y tendrás una "Vista", que es muy parecido a [MVC] - una arquitectura OOP común para
la mayoría de los [frameworks](/#frameworks).

**foo.php**

{% highlight php %}
<?php
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8mb4', 'username', 'password');
// Make your model available
// Ponga su modelo a disposición
include 'models/FooModel.php';
// Create an instance
// Crear una instancia
$fooModel = new FooModel($db);
// Get the list of Foos
// Obtener la lista de Foos
$fooList = $fooModel->getAllFoos();

// Show the view
// Mostrar la vista
include 'views/foo-list.php';
{% endhighlight %}

Expand Down Expand Up @@ -88,9 +87,9 @@ class FooModel
<?php endforeach ?>
{% endhighlight %}

This is essentially the same as what most modern frameworks are doing, albeit a little more manual. You might not
need to do all of that every time, but mixing together too much presentation logic and database interaction can be a
real problem if you ever want to [unit-test](/#unit-testing) your application.
Esto es esencialmente lo mismo que hacen la mayoría de los frameworks modernos, aunque un poco más manual.
Puede que no necesites hacer todo eso cada vez, pero mezclar demasiada lógica de presentación e interacción con la base de datos
puede ser un verdadero problema si alguna vez quieres hacer [test unitarios](/#test-unitarios) a tu aplicación.


[MVC]: https://code.tutsplus.com/tutorials/mvc-for-noobs--net-10488
13 changes: 6 additions & 7 deletions _posts/07-05-01-Abstraction-Layers.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@ anchor: capas_de_abstraccion_de_bases_de_datos

## Capas de Abstracción {#capas_de_abstraccion_de_bases_de_datos_title}

Many frameworks provide their own abstraction layer which may or may not sit on top of [PDO][1]. These will often
emulate features for one database system that is missing from another by wrapping your queries in PHP methods, giving
you actual database abstraction instead of just the connection abstraction that PDO provides. This will of course add a
little overhead, but if you are building a portable application that needs to work with MySQL, PostgreSQL and SQLite
then a little overhead will be worth it for the sake of code cleanliness.
Muchos frameworks proporcionan su propia capa de abstracción que puede o no sentarse encima de [PDO][1].
Estos a menudo emulan características de un sistema de base de datos que falta en otro envolviendo sus consultas en métodos PHP,
dándole abstracción de base de datos real en lugar de sólo la abstracción de conexión que PDO proporciona. Esto, por supuesto,
añadirá un poco de sobrecarga, pero si usted está construyendo una aplicación portable que necesita trabajar con MySQL,
PostgreSQL y SQLite entonces un poco de sobrecarga valdrá la pena por el bien de la limpieza del código.

Some abstraction layers have been built using the [PSR-0][psr0] or [PSR-4][psr4] namespace standards so can be
installed in any application you like:
Algunas capas de abstracción se han construido utilizando los estándares de espacio de nombres [PSR-0][psr0] o [PSR-4][psr4], por lo que pueden instalarse en cualquier aplicación que se desee:

* [Atlas][5]
* [Aura SQL][6]
Expand Down
2 changes: 1 addition & 1 deletion _posts/11-02-01-Test-Driven-Development.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ From [Wikipedia](https://wikipedia.org/wiki/Test-driven_development):
There are several different types of testing that you can do for your application:

### Unit Testing
### Test Unitarios

Unit Testing is a programming approach to ensure functions, classes and methods are working as expected, from the point
you build them all the way through the development cycle. By checking values going in and out of various functions and
Expand Down

0 comments on commit 6250d28

Please sign in to comment.