PHPSymfony - Blog par un programmeur pour les programmeurs

To content | To menu | To search

Tuesday, September 16 2014

[Debian] Résoudre le problème de mise à jour des packages sur squeeze NO_PUBKEY 8B48AD6246925553

Vous êtes sous Debian Squeeze et lorsque vous lancez un simple apt-get update, vous obtenez :


W: Une erreur s'est produite lors du contrôle de la signature. Le dépôt n'est pas mis à jour et les fichiers d'index précédents seront utilisés. Erreur de GPG : http://ftp.fr.debian.org squeeze-updates Release : Les signatures suivantes n'ont pas pu être vérifiées car la clé publique n'est pas disponible : NO_PUBKEY 8B48AD6246925553

W: Impossible de récupérer http://ftp.fr.debian.org/debian/dists/squeeze-updates/Release

W: Le téléchargement de quelques fichiers d'index a échoué, ils ont été ignorés, ou les anciens ont été utilisés à la place.



La commande suivante vous permettra d'installer les nouvelles clés et de ne plus rencontrer cette erreur

sudo apt-get install debian-archive-keyring

Friday, May 30 2014

[Vagrant] Travailler dans un environnement avec un proxy HTTP

Installer le plugin de gestion de proxy

vagrant plugin install vagrant-proxyconf

Configurer le fichier VagrantFile en ajoutant les lignes suivantes :


Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  ...

  if Vagrant.has_plugin?("vagrant-proxyconf")
    config.proxy.http     = "http://X.X.X.X/"
    config.proxy.https    = "http://X.X.X.X/"
    config.proxy.ftp      = "http://X.X.X.X/"
    config.proxy.no_proxy = "localhost,127.0.0.1,.example.com"
  end

...
où vous remplacerez X.X.X.X par l'IP de votre proxy.
Lancez votre machine virtuelle, puis une fois connecté sur votre VM en SSH, lancez simplement un export pour vérifier que les paramètres ont été correctement appliqués.

Thursday, May 22 2014

Bouchonner ou mocker des appels à des services SOAP avec SoapUI

Dans le cadre d'une mission chez un client, nous avions besoin de rapatrier des données existantes chez l'un de ses partenaires.
Ce partenaire exposait la liste de ses services via une API SOAP. De son côté, il disposait d'offres spéciales liées à une ou plusieurs catégories marketing.
Nous voulions récupérer ces données dans notre système pour faire notre propre système de promotions.
 
Notre gentil Product Owner nous a demandé par la suite une évolution. Nous devions ajouter des règles de gestion dans notre système en fonction des valeurs retournées par le service.
Il y avait plusieurs cas à tester. Lors de la phase de tests, nous avons constaté que les données retournées par le service du partenaire ne nous permettaient pas de tester tous les cas possibles.

Nous avons donc décidé de bouchonner le service pour en contrôler le retour, pour pouvoir tester tous les cas possibles.

Après quelques recherches, nous avons mis en évidence le logiciel SoapUI qui permet de bouchonner un webservice.
Même s'il existe une documentation, j'ai trouvé celle-ci peu détaillée surtout dans des cas de bouchonnage avancé.

Dans cet article, je proposerai donc un exemple de 3 bouchons :
 - un bouchon simple : même réponse retournée quelque soit la requête
 - un bouchon avancé avec sélection de la réponse en fonction des données de la requête
 - un bouchon avancé : le corps de la réponse est scripté en fonction des paramètres de la requête

A noter : Le service que nous utilisions étant privé, je ne peux l'exposer publiquement sur ce blog (puis ça vous servirai à rien ...).
Je vais le remplacer par un webservice public de récupération des valeurs boursières. A partir d'un identifiant de société, le service retourne diverses informations.

http://www.webservicex.com/stockquote.asmx?WSDL


Configuration SoapUI


Première étape, installer SoapUI : http://www.soapui.org/

On commence par créer un projet "New Soap Project" et on renseigne l'adresse du WSDL : http://www.webservicex.com/stockquote.asmx?WSDL
01_new_project

Laissez cocher "Create sample request for all operation".

SoapUI génère alors la liste des opérations à partir du descripteur.
Vous pouvez faire un essai avec le code AAPL (société APPLE).

02_query_aapl_example


Nous allons maintenant créer le bouchon de ce service. Clic-doit sur le projet, puis "New SOAP MockService", puis donnez lui un nom.
C'est dans à MockService que seront liées nos MockOperation.

Cas 1 : bouchon simple : même réponse retournée quelque soit l'appel


Dans ce premier exemple, nous allons faire en sorte que le bouchon retourne toujours la même réponse. Nous allons adapter légèrement la réponse que nous avions obtenu juste avant avec Apple. On utilisera la société avec le code GUIGUI.


<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <soap:Body>
      <GetQuoteResponse xmlns="http://www.webserviceX.NET/">
         <GetQuoteResult><![CDATA[<StockQuotes><Stock><Symbol>GUIGUI</Symbol><Last>612.20</Last><Date>5/23/2014</Date><Time>12:07pm</Time><Change>+1.62</Change><Open>607.25</Open><High>608.93</High><Low>606.47</Low><Volume>1000</Volume><MktCap>524.5B</MktCap><PreviousClose>607.27</PreviousClose><PercentageChange>+0.27%</PercentageChange><AnnRange>388.87 - 609.85</AnnRange><Earns>41.727</Earns><P-E>14.55</P-E><Name>Guigui Corp</Name></Stock></StockQuotes>]]></GetQuoteResult>
      </GetQuoteResponse>
   </soap:Body>
</soap:Envelope>



Nous allons maintenant créer le bouchon sur SoapUI.
Clic droit sur le MockService, puis, sélectionnez l'opération à bouchonner, puis validez. SoapUI créé alors la MockOperation et affiche une nouvelle fenêtre contenant le bouchon ou la MockResponse. Coller le contenu du code précédent dans la colonne de droite de votre MockResponse.

03_create_soap_mock

04_mock_operation_creation

Dès lors que SoapUI recevra une requête liée à l'opération GetQuote, il retournera systématiquement la réponse que vous avez saisi.
Il faut maintenant lancer le serveur SOAP de SoapUI.

05_soapui_mock_server_start

Le serveur est lancé, par défaut il tourne sur le port 8080. En cliquant sur la 3e icône à droite de l'icône de lancement du serveur, vous ouvrez alors dans votre browser le WSDL. Par exemple : http://localhost:8080/?WSDL

Donnez ensuite cette adresse dans la configuration de votre client SOAP de telle manière à ce qu'il attaque le bouchon et non plus le vrai serveur. Ou sinon, vous pouvez utiliser SoapUI lui-même !

Lancez la requête suivante :

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://www.webserviceX.NET/">
   <soapenv:Header/>
   <soapenv:Body>
      <web:GetQuote>
         <!--Optional:-->
         <web:symbol>WTF</web:symbol>
      </web:GetQuote>
   </soapenv:Body>
</soapenv:Envelope>



SoapUI retournera alors le contenu de la MockResponse que vous avez renseigné.


Cas 2 : bouchon avancé avec sélection de la réponse en fonction des données de la requête

Le bouchon simple est pratique. A peu près 5 minutes. Ensuite, vous voudrez passer à la vitesse supérieure. Vous voudrez sans doute retourner des réponses différentes en fonction des requêtes pour pouvoir simuler différents cas.
Par exemple, on veut que le bouchon retourne des réponses différentes en fonction du code symbole dans la requête.
Si on saisit GUIGUI, on s'attend à avoir GUIGUI en code société dans le corps de la réponse.
Si on saisit PLOP, on s'attend à avoir PLOP dans le corps de la réponse.
Je vais m’arrêter là, vous avez compris le principe (du moins je l'espère)
On ne traitera que ces 2 cas pour le moment.

On commence alors par créer deux MockResponse : un contenant la réponse avec le code GUIGUI et l'autre avec le code PLOP.
Nous allons ensuite aborder la notion de dispatch au niveau de la MockOperation.

06_MockOperation_dispatch

Nous allons utiliser un dispatch de type QUERY_MATCH. Ce mode de dispatch va appliquer une requête xpath sur la requête. Si le retour de la requête correspond à un attendu, alors SoapUI retournera une MockResponse particulière.

Nous allons créer des critères de match :

07_query_match_creation

Dans le textarea "xpath", saisissez la requête suivante :

declare namespace soapenv='http://schemas.xmlsoap.org/soap/envelope/';
declare namespace web='http://www.webserviceX.NET/';
//web:symbol/text()



Indiquez ensuite la valeur attendue dans le textarea "Expected Value :"

Puis la MockResponse à utiliser dans "Dispatch To"

08_mock_operation_dispatch_query_configured

Vous pouvez ensuite lancer vos tests (n'oubliez pas de démarrer le serveur de SoapUI si vous l'aviez coupé entre temps, petites têtes).
Puis, essayez de lancer les requêtes avec les 2 valeurs GUIGUI et PLOP. SoapUI vous retournera alors les réponses différentes.


Cas 3 : bouchon avancé : le corps de la réponse est scripté en fonction des paramètres de la requête

Le cas précédent est pratique car il permet de sélectionner une réponse à partir de paramètres dans la requête. Cependant, il y aura (surement) des contextes dans lesquels vouss voudrez dynamiser davantage vos réponses.

Avec la solution précédente, que se passe-t-il si vous devez requêter 500 codes différents ?
Cela signifie la création de 500 MockResponses et 500 règles ?! C'est hors de question :)
Nous allons utiliser une réponse unique que nous allons dynamiser en la scriptant !

Avant de continuer dans le domaine du scripting, il est bon de rappeler que SoapUI utilise Groovy comme langage de script par défaut.
SoapUI propose toutefois la possibilité d'utiliser du javascript. Je dois vous mettre en garde toutefois, les ressources disponibles avec du code javascript ne sont pas légion. Si vous faites le choix du javascript, attendez vous à galérer un peu. Ou sinon apprennez le Groovy (et cassez pas les ...).

Pour le changement du langage de script, cela se fait au niveau du projet. Cliquez sur le projet, puis regarder l'onglet "Project properties".
Dans la liste, changer la valeur du paramètre "Script language" en "Javascript".

Commencez par créer une MockOperation pour votre opération, puis laissez le dispatch en SEQUENCE.

Dans la MockResponse associée, saisissez :

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <soap:Body>
      <GetQuoteResponse xmlns="http://www.webserviceX.NET/">
         <GetQuoteResult><![CDATA[<StockQuotes><Stock><Symbol>${code}</Symbol><Last>${value}</Last><Date>5/23/2014</Date><Time>12:07pm</Time><Change>+1.62</Change><Open>607.25</Open><High>608.93</High><Low>606.47</Low><Volume>1000</Volume><MktCap>524.5B</MktCap><PreviousClose>607.27</PreviousClose><PercentageChange>+0.27%</PercentageChange><AnnRange>388.87 - 609.85</AnnRange><Earns>41.727</Earns><P-E>14.55</P-E><Name>Guigui Corp</Name></Stock></StockQuotes>]]></GetQuoteResult>
      </GetQuoteResponse>
   </soap:Body>
</soap:Envelope>



Vous avez surement noté ${code} et ${value}. Il s'agit ici de variables (vous le saviez, vous êtes des petits futés !). Une variable pour le code symbole et l'autre pour la valeur.
Avec ces paramètres, nous allons dynamiser notre réponse. On remplacera ${code} par le code contenu dans la requête et ${value} par un montant aléatoire.

Dans la MockResponse, tout en bas, vous disposez de boutons. Cliquez sur le bouton "script". Vous verrez alors apparaitre un éditeur.

Dans cet éditeur, renseignez le code suivant :


var amount = parseInt(Math.floor((Math.random() * 1000 ) + 1));
var code = mockRequest.getContentElement().selectPath("declare namespace soapenv='http://schemas.xmlsoap.org/soap/envelope/'; declare namespace web='http://www.webserviceX.NET/'; //web:symbol/text()");

context.setProperty('code', code[0].stringValue());
context.setProperty('value', amount);


Quelques explications s'imposent :
Dans un premier temps, on va générer la valeur amount via les fonctions de Math.random() de javascript.
Dans un second temps, on va extraire l'information de code depuis la requête pour la placer dans une variable.
Puis, on envois ces données à la MockResponse qui fera le remplacement.

09_mockresponse_scripting_javascript_soapui

A nouveau, lancez le serveur SoapUI si vous l'aviez arrêté. Vous pourrez ainsi tester des cas avec une partie aléatoire et une partie pré déterminée !

Pour finir ...


Nous avons vu 3 cas pratiques de bouchonnage. Mais il existe d'autres possibilités offertes par SoapUI. Vous pouvez par exemple faire en sorte que certaines réponses retournent des SOAP Fault de telle manière à tester le bon fonctionnement de vos mécanismes de gestion des erreurs, et bien plus encore ...

Thursday, May 8 2014

VirtualBox - Configurer une VM VirtualBox pour un ordinateur portable itinérant sous Windows

Si comme moi vous avez un PC portable pro, dans le cadre de vos déplacements, vous êtes surement amenés à vous connecter sur différents réseaux, chacun ayant sa propre politique en matière de DHCP (sans compter votre réseau perso).
Si, de plus, vous utilisez des VM avec VirtualBox sans configuration particulière, cela signifie que les adresses IP de vos VM sont susceptibles de changer. Vous êtes alors systématiquement obligés de démarrer votre VM manuellement pour y récupérer l'IP via un ifconfig pour ensuite lancer votre putty ... etc ... Bref, pas très pratique...

Il existe néanmoins une solution. En combinant une interface "Accès par pont" et une interface "Réseau privé hôte", vous pourrez accéder au réseau sur lequel vous êtes actuellement connecté (et éventuellement acceder à Internet) et également conserver une IP fixe pour vous connecter sur vos VM, en SSH par exemple.

Commencez d'abord par créer une configuration de réseau hôte uniquement. Ca se passe dans Fichier > Paramètres > Réseau > Onglet Réseau Hôte uniquement







Puis ensuite, il faut modifier la configuration de la VM que l'on souhaite utiliser :

On configure la première interface en "Accès par pont" :



Puis la deuxième en "Réseau privé Hôte" :




Ensuite, on démarre la VM et on édite le fichier /etc/network/interfaces pour y renseigner la configuration suivante :




Après un redemarrage du service, c'est terminé !

NB : Cette configuration a été réalisée avec VirtualBox 4.3.10 et une Debian Wheezy 7.5 sous Windows 7.

Tuesday, March 11 2014

[PHP] Modifier la configuration de PHP pour l'exécution d'un script en CLI

Souvent, alors que j'utilise composer sur mon poste de dev, mon script plante car la mémoire est saturée. Pour ce genre d'opérations, il est possible de modifier des configurations du php.ini via l'argument -d (ou --define). Cela donne par exemple :

php -d memory_limit=-1 composer.phar update

[PHP][BEHAT] Utilisation de Behat/Mink pour tester une application web

Au cours du développement d'un projet chez un client, nous avions la volonté de pouvoir livrer plus vite nos versions applicatives. Cela devait nous permettre de pousser rapidement nos fix en production mais également de réduire le time to market des fonctionnalités clés. Difficile de ne pas être d'accord avec cette idée. Quand nous l'avons présenté aux référents Agile, il nous ont alors répondu : "Ok si vous améliorez la qualité de vos livraisons". Nous avons alors fais le point sur comment améliorer la qualité générale de nos livrables. Un point qui est ressorti de ces réunions est la lourdeur de certaines phases de tests.
En effet, nous avons dans notre cycle une phase de préparation pendant laquelle nos testeurs se chargent de vérifier le bon fonctionnement des anciennes et des nouvelles fonctionnalités. Cette phase, avant la mise en production, est très longue (2 semaines) et est essentiellement manuelle. Nous avons alors décidé de mettre en place du test fonctionnel automatisé. Nous avons alors étudié et mis en place la solution behat : http://behat.org/

Présentation


Behat


Behat est un framework pour faire du BDD. BDD pour “Behavior Driven Development”. Qu’est-ce que le Behavior Driven Development ?

Je citerai l’article sur Wikipédia (http://fr.wikipedia.org/wiki/Behavior_Driven_Development) : Il s’agit d’une « méthode Agile qui encourage la collaboration entre les développeurs, les responsables qualité, les intervenants non techniques participants à un projet logiciel. »

« Le processus BDD met en avant le langage naturel et les interactions dans le processus de développement logiciel. Les développeurs utilisant le BDD utilisent leur langue maternelle en combinaison avec le langage du domaine Domaine Driven Design pour décrire l'objectif et le bénéfice de leur code. Cela permet aux développeurs de se concentrer sur les raisons pour lesquelles le code doit être créé, plutôt que les détails techniques, et minimise la traduction entre le langage technique dans laquelle le code est écrit et le domaine de la langue parlée par les entreprises, les utilisateurs, les intervenants, la gestion de projet… ».

En synthétisant : on écrit des scénarios en langage lisible par l’homme qui décrit le comportement de l’application. Ces scénarios peuvent être testés automatiquement sur l’application. Et c’est super.

En PHP, il existe Behat : http://behat.org/

Behat permet de faire du BDD en PHP. C’est un utilitaire à lancer en ligne de commande. Il permet de tester le fonctionnement d’une application. Sur leur site internet, ils proposent un exemple avec la fonction « ls ».

Behat seul ne permet pas de tester des applications avec UI. Il est rare qu’un client vous demande une application en ligne de commande ; le plus souvent le produit en question va être constitué de pages web, d’interfaces graphiques riches. Qu’à cela ne tienne, il existe un outil que l’on couplera avec Behat, il s’agit de Mink.



Mink

Dans une application web, l’une des parties les plus importantes est le navigateur. C’est dans le navigateur que l’internaute va interagir avec l’application. Afin de garantir que notre application fonctionne correctement, nous devons la tester. Nous devons donc trouver un moyen de simuler les interactions d’un navigateur web avec notre application. C’est ici que Mink entre en jeu.

Avant de rentrer dans le détail de Mink, il faut savoir qu’il existe un grand nombre d’émulateurs de navigateurs (Ex : Goutte, Selenium, Sahi), qu’on appellera browser emulators (cela fait plus classe en soirée).  Ils font le même job mais de manière différente. Ils se comportent différemment et disposent d’API différentes. Il existe par ailleurs 2 types de browser emulators.

-          Les émulateurs sans tête (headless)

Ces types d’émulateurs sont simples à installer et à configurer. Par exemple de Goutte de Fabien Potencier. Ils permettent d’envoyer des requêtes HTTP à un serveur web et parsent la réponse. Ils peuvent être facilement lancés sur un serveur sans UI en mode console et sont très rapides. Cependant, le gros inconvénient est qu’ils ne gèrent pas le javascript. Il n’est donc pas possible de tester des interfaces graphiques riches avec du contenu en Ajax.  Néanmoins, ce type d’émulateur peut être pratique pour tester des APIs REST.

-          Les émulateurs qui contrôlent les navigateurs

Ces émulateurs permettent de contrôler de véritables navigateurs. Ce type d’émulateurs va permettre de simuler les interactions d’un utilisateur sur le navigateur. Selenium et Sahi sont 2 exemples connus et utilisés. Ce type d’émulateur à l’avantage de proposer le support du javascript et de l’Ajax pour tester les applications web riches. En revanche, il faut que les navigateurs soient installés sur la machine, la configuration est moins aisée et les tests seront plus longs que les émulateurs headless.

Chaque type d’émulateur a ses avantages et ses inconvénients. De ce fait, il faut les utiliser tous les deux pour tester efficacement. Et Mink va nous le permettre.

Mink permet de travailler avec les différents émulateurs via la notion de driver. Mink est une couche d’abstraction d’émulateur de navigateurs. Il masque les subtilités des différents émulateurs à travers une API unique et simple.




Installation du projet


Pour présenter l'utilisation de behat, j'ai créé un repo sous github https://github.com/guiguiboy/session-behat avec une application sous Silex (histoire d'avoir un site qui ne réponde pas systématiquement Hello world".


mkdir /var/www/session-behat
git clone https://github.com/guiguiboy/session-behat .
php composer.phar install


Pour ceux qui ne sont pas inspirés, vous trouverez dans le dossier doc/ un exemple de virtual host Apache.

Essayez de faire tourner l'application sur votre navigateur. Si il y a un problème il faut le résoudre avant de passer à l'étape de mise en place des tests fonctionnels.


Utilisation

Commencez par vous placer dans le répertoire de votre projet. Sur mon poste, cela donne :

cd /var/www/session-behat

Vous trouverez l'arbo suivante :
  • src : les sources de la web app
  • bin : les exécutables
  • doc : la documentation
  • test : où sont entreposés les fichiers de tests et de config de behat

Ensuite, vous pourrez lancer les tests. Mais d'abord, commençons déjà par voir le dictionnaire de behat. On utilisera l'argument -dl :

php bin/behat -c test/functional/behat.yml -dl

NB : on doit indiquer le path vers le fichier de configuration behat.yml avec l'argument -c si on travaille depuis la racine du projet. On obtient une liste de toutes les étapes que nous pouvons utiliser de manière builtin dans nos fichiers de feature.

Toutes ces étapes pourront être indiquées dans nos fichiers de feature.

Nous allons voir notre premier fichier de feature : un test sur la connexion. J'ai créé des routes /login accessible en GET et en POST pour contrôler les identifiants d'un utilisateur. J'ai identifié des identifiants corrects qui sont guiguiboy:plop (non, ce n'est pas mon vrai mot de passe). J'ai créé le fichier de feature suivant :

[10:15]user@gm21:/var/www/session-behat$ cat test/functional/features/login.feature
Feature: Login

  Scenario: Scenario with bad login values provided
    Given I am on "/login"
    When I fill in "login[username]" with "pwet"
    And I fill in "login[password]" with "lolilol"
    And I press "login[submit]"
    Then I should see "bad login/password provided"

  Scenario: Scenario with correct login values provided
    Given I am on "/login"
    When I fill in "login[username]" with "guiguiboy"
    And I fill in "login[password]" with "plop"
    And I press "login[submit]"
    Then I should see "Welcome, guiguiboy"



Ce fichier de feature est composé de 2 tests : un premier qui doit permettre de contrôler l'affichage d'une erreur si le sidentifiants de connexion ne sont pas reconnus, puis un deuxième permettant de contrôler le bon affichage d'une chaîne lorsque les identifiants sont corrects. Les différentes étapes sont simples, pour identifier les champs du formulaire, on utilise leur name (il est également possible de les identifier par id, label ou valeur).

Pour lancer les tests, on utilise la commande :

php bin/behat -c test/functional/behat.yml

Par défaut, tous les fichiers de feature seront joués. Il est cependant possible de ne spécifier qu'un seul fichier en le passant directement en argument :

php bin/behat -c test/functional/behat.yml test/functional/features/login.feature

Behat affiche alors un rapport sur la suite de tests. Une étape validée est affichée en vert, une étape en erreur est affichée en rouge et des indications sont données.

Un pro-tip, pour "debogger" un test, il est possible d'utiliser 3 étapes built in :
 Then /^print current URL$/
 Then /^print last response$/
 Then /^show last response$/

Ces deux dernières étapes permettent alors d'afficher le code HTML au moment du test, qui permettra de comprendre pourquoi une étape échoue.

Cet article est simple et présente vraiment la base du fonctionnement de behat/mink. Il existe d'autres fonctions très utiles comme les :
  •  scenario outline
  •  possibilité de définir ces propres étapes,
  • mise en place de backgrounds,
  • ...
Ils feront (ou pas !) l'objet d'articles supplémentaires sur ce blog ...

Tuesday, November 26 2013

[PHP] Réflexion - Un requêteur SQL en live sur vos applications PHP : la fausse bonne idée

Au cours d'un de mes projets PHP, un client nous a demandé la possibilité de pouvoir exécuter des requêtes SQL en live via une interface dans l'administration de son site.
Le but n'était pas de recoder un PHPMyAdmin mais uniquement de pouvoir faire des requêtes de type SELECT pour récupérer rapidement des données sans l'intervention des développeurs. Les données s'affichant dans un tableau HTML ou au format CSV. Enfin, notre client souhaitait que les requêtes puissent être enregistrées afin de pouvoir les rejouer à la demande.
Cette fonctionnalité partait d'un bon sentiment, via cette interface, on pouvait sortir rapidement des données. Cela évitait de rentrer dans une phase de développement et réduisait le time to market.

Mais ne tombez pas dans le piège de ce développement.
Voilà les principales raisons qui font du requêteur SQL en live une mauvaise fonctionnalité.

La sécurité de la BDD

La sécurité est bel et bien le premier point à considérer. En tant que développeur, nous nous devons d'assurer le bon fonctionnement de l'application sur laquelle nous travaillons.
De ce fait, même si l'on se dit que l'on veut exécuter uniquement des requêtes de type SELECT, comment peut on s'en assurer ?
Comment peut-on éviter qu'un utilisateur ne contourne le système en faisant des requêtes de type INSERT, ou pire, des DELETE, ALTER TABLE, TRUNCATE, DROP ... ?
On commence alors à chercher un pattern de requête autorisées. Si celles-ci commencent par des commandes interdites, alors c'est qu'elles ne sont pas autorisées.
C'est le développement que la plupart des développeurs feront. Tant et si bien que si la requête SQL est préfixée par un commentaire, /**/, celle-ci sera tout de même exécutée.
Il faudra alors penser à encapsuler les requêtes formulées dans une connexion particulière avec des droits restreints et à switcher correctement entre vos connexions.

Impacts sur la performance de votre site

Une requête SQL avec une erreur de syntaxe est rapidement détectée et n'a pas beaucoup d'impacts négatifs. En revanche, les erreurs de logique sont plus dangereuses. Imaginez qu'un opérateur saisisse une requête qui fait le produit cartésien de 2 tables avec plusieurs milliers de lignes sans clause de LIMIT. Le serveur de base de données va être fortement sollicité pour effectuer le calcul. Les performances de votre site risquent donc d'être directement impactées.

La mémoire elle aussi fortement sollicitée. Si vous utilisez le driver mysqlnd pour PHP, vous savez que les résultats d'une requête sont directement stockées dans la mémoire de PHP. Ainsi, si votre requête vous retourne de nombreux résultats et que vous récupérer la totalité du resultset, vous risquez de saturer la mémoire allouée à PHP.

La sécurité des données

Toujours dans le thème de la sécurité, il faut également considérer la sécurité des données. Vous avez un SI et vous avez défini des droits dans ce SI.
Un utilisateur lambda ne peut pas avoir accès à certaines informations. Avec un système de requêteur SQL en live, vous prenez le risque que certaines personnes non autorisées puissent accéder à des informations sensibles.

Posez vous la question suivante : êtes-vous complètement irréprochables et est-ce que toutes vos données critiques sont masquées ? Par exemple, est-ce que vous stockez en clair les mots de passe de vos clients ? Si oui, c'est vraiment très mal et vous devriez sérieusement songer à changer cela (!). Mais la n'est pas la question, il y a des données sensibles qui peuvent être exploitées par une personne mal intentionnée.

On peut éventuellement restreindre l'accès en lecture à certaines tables à certains utilisateurs. Cependant, cette configuration devra être directement faite sur le SGBD.
Vous perdrez alors en souplesse au niveau de votre application. Pire, vous devrez systématiquement vous demander, à chaque modification de schéma, quels utilisateurs peuvent accéder à vos nouvelles tables pour ensuite transmettre l'information à vos administrateurs système.

Les données exportées sont fausses à un instant t

Qui mieux que les développeurs savent comment sont stockées et organisées les données dans une base ? Personne. Surtout pas le client, qui la plupart du temps n'a aucune connaissance technique.
Du coup, vous aurez besoin d'un développeur pour vous aider à faire une requête. Sans son aide, vous prenez le risque de sortir des mauvaises informations.
En effet, vous n'avez peut-être pas vu ce champs deleted_at qui permet de supprimer logiquement une ligne. Ce qui fait que votre requête ne donnera pas les résultats que vous attendiez.
Ainsi, alors que vous pensiez gagner du temps, vous aller demander à votre développeur de vous sortir telle ou telle requête entre 2 développements.
Vous n'allez de plus certainement pas créer de demande écrite pour une simple requête SQL. Le temps que votre développeur y consacrera n'apparaitra nulle part.

Les données exportées sont fausses à un instant t+1

C'est encore pire lorsque les requêtes sont enregistrées pour être rejouées à la demande. Comme vous le savez, la base de données est liée à une application. Pour que l'application puisse proposer de nouvelles fonctionnalités, la base de données doit évoluer en conséquence.
De ce fait, une requête formulée à un instant t risque de ne plus être valable à un instant t+1.
Par ailleurs, vous n'aurez aucun système pour vous assurer que les données retournées par une requête sont correctes. Vous ne pourrez que tester la syntaxe de votre ordre SQL. Vous ne pourrez pas tester le résultat attendu, comme vous pourriez le faire avec un test unitaire.

Conclusion

Personnellement, pour toutes les raisons évoquées ci-dessus, je décourage fortement l'utilisation d'une fonction de requêteur SQL en live dans votre application. Je recommande le développement d'interfaces spécifiques pour sortir les données en fonction des besoins. En développant ces interfaces, vous allez écrire des tests, unitaires et fonctionnels. Ces tests permettront de garantir le bon fonctionnement de votre application au fur et à mesure des évolutions fonctionnelles. Vous maitriserez mieux le code applicatif.
Vous pourrez également utiliser d'autres outils d'intelligence économique comme Business Objects qui vous offriront plus de possibilités. Néanmoins, le déploiement de ces outils a un coût.

Tuesday, October 22 2013

[PHP] Utiliser firePHP pour debugger les applis sous Firefox

Cela faisait un petit moment que je voulais regarder ce que c'était et comment ça marchait. J'ai profité d'avoir un peu de temps pour installer FirePHP. Voici comment j'ai procédé :

Il y a des actions à réaliser côté client et côté serveur :

Côté client

  • Installer firefox
  • Installer l'extension Firebug via le gestionnaire d'add-ons Firefox : https://addons.mozilla.org/en-US/firefox/addon/firebug/?src=search
  • Installer l'extension FirePHP via le gestionnaire d'add-ons Firefox : https://addons.mozilla.org/en-US/firefox/addon/firephp/

Côté serveur

wget http://www.firephp.org/DownloadRelease/FirePHPLibrary-FirePHPCore-X.X.X

Attention : X.X.X à remplacer par la version souhaitée

unzip FirePHPLibrary-FirePHPCore-0.3.2.1

copiez le dossier créé dans un répertoire auquel votre projet PHP peut accéder

Dans votre script, insérez les lignes suivantes


Si vous lancez votre navigateur, vous verrez alors apparaitre un message de debug dans votre Firebug.

Pour plus d'informations sur FirePHP : http://www.firephp.org/HQ/Use.htm

Je précise que FirePHP n'est à utiliser que sur l'environnement de développement de votre projet.
Vous devez être capables, par configuration, de désactiver son utilisation en fonction de vos environnements.

Cela faisait un petit moment que je voulais regarder cette extension et comment l’implémenter (il n'est jamais trop tard !).
Personnellement, je vais essayer pour voir ce que ça donne. Mais, dans une certaine mesure uniquement. En effet, je me suis familiarisé depuis peu avec le TDD et j'ai de moins en moins besoin de ce genre d'outils.

Monday, September 30 2013

Activer / désactiver phpmyadmin sur un serveur Debian par script

Voici un petit script qui permet d'activer / désactiver phpmyadmin sur un serveur de type Debian.


Pour l'activation  :

./pma.sh "up"


Pour la désactivation :

./pma.sh "down"

Sunday, May 12 2013

Demarrer avec un Raspberry Pi Model B

Dans cet article, je vais expliquer comment faire ses premiers pas avec un raspberry pi. L'idée est de le connecter simplement à un réseau filaire existant et de pouvoir ensuite se connecter via putty.

Si vous ne savez ne savez pas ce qu'est un raspberry pi, je vous encourage à aller lire la page suivante qui présente bien le produit : www.kubii.fr/content/19-raspberry-pi-model-b-512-mo-presentation

Concernant l'achat, je suis passé par le site de farnell : http://fr.farnell.com/

J'y ai acheté :
  • raspberry pi Model B
  • un cable rj45 3M
  • un cable USB vers micro USB

Pour un cout de 52€ livraison comprise.

J'ai commandé la carte mémoire séparément. D'après la liste des cartes compatibles dispo sur http://elinux.org/RPi_SD_cards j'ai choisi, une SANDISK 16Go Extreme SDSDX-016G-X46 (en promo chez grosbill  : http://www.grosbill.com/4-sandisk_16go_extreme_-144521-numerique-memoire_sd_card)

Une fois, votre mini ordinateur et la carte mémoire recus, nous allons pouvoir commencer.

Tout d'abord, munissez vous d'un lecteur de carte SD (la plupart des PC portables en ont un intégré). Télécharger sur la page http://www.raspberrypi.org/downloads la raspbian wheezy. Téléchargez également Win32 diskimager http://sourceforge.net/projects/win32diskimager/?source=dlp si vous êtes sous windows. Insérez la carte dans le lecteur de cartes. Copiez l'image sur la carte grace au logiciel.

Insérez ensuite la carte dans le raspberry pi et connectez le à une source d'alimentation via le cable micro USB. Raccordez le RPi au réseau via le cable RJ45. La distribution installée est équipée d'un serveur ssh et les identifiants par défaut sont :

  • login : pi
  • password : raspberry

Si vous réseau est équipée d'un serveur DHCP, vous pourrez connaitre l'IP du raspberry pi via l'outil http://www.softperfect.com/products/networkscanner/

Les adresses MAC des raspberry pi débutent par B8:27:EB. Une fois l'adresse IP récupérée, vous pourrez vous connecter en ssh via un outil type putty.

Tuesday, October 2 2012

[Linux] Changer l'adresse MAC sous Ubuntu 11.10

Pour changer l'adresse MAC de votre carte réseau sous Ubuntu 11.10 :

  • Affichez les interfaces actives via la commande ifconfig :

[08:55]user@gm21:/home/guigui$ sudo ifconfig
eth0      Link encap:Ethernet  HWaddr 08:00:27:ef:b8:71
          inet adr:172.25.10.60  Bcast:172.25.11.255  Masque:255.255.254.0
          adr inet6: fe80::a00:27ff:feef:b871/64 Scope:Lien
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:755506 errors:0 dropped:0 overruns:0 frame:0
          TX packets:2746 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 lg file transmission:1000
          RX bytes:81288103 (77.5 MiB)  TX bytes:354363 (346.0 KiB)

eth1      Link encap:Ethernet  HWaddr 08:00:27:0a:92:d5
          inet adr:192.168.56.101  Bcast:192.168.56.255  Masque:255.255.255.0
          adr inet6: fe80::a00:27ff:fe0a:92d5/64 Scope:Lien
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:12701342 errors:0 dropped:0 overruns:0 frame:0
          TX packets:12732288 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 lg file transmission:1000
          RX bytes:2847332852 (2.6 GiB)  TX bytes:2772354787 (2.5 GiB)

lo        Link encap:Boucle locale
          inet adr:127.0.0.1  Masque:255.0.0.0
          adr inet6: ::1/128 Scope:Hôte
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:1667 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1667 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 lg file transmission:0
          RX bytes:116698 (113.9 KiB)  TX bytes:116698 (113.9 KiB)$


  • Arrétez  le network manager

sudo service network-manager stop


  • Changez l'adresse MAC de l'interface concernée

sudo ifconfig ethX hw ether xx:xx:xx:xx:xx:xx

où vous remplacerez ethX par une interface existante et xx:xx:xx:xx:xx:xx  par une adresse MAC valide (08:00:27:42:01:11 par exemple). S'il s'agissait d'une carte réseau sans fil, remplacez ethX par wlanX.

 

  • Relancer le network manager

sudo service network-manager start


  • Vérifier la prise en compte des informations par une nouvelle commande ifconfig

sudo ifconfig

Attention, cette modification est temporaire, lorsque vous redémarrerez votre machine, l'ancienne valeur de l'adresse MAC sera rétablie.

Friday, August 17 2012

[Javascript][Mootools] Requêtes périodiques avec Mootools

Dans le cadre d'un développement, j'ai du implémenter une fonctionnalité de requête périodique sur un de mes sites web pour vérifier par exemple :

  • la disponibilité d'un service,
  • un nombre de personnes connectées,
  • ...

J'ai donc créé la classe générique PeriodicRequest pour répondre à ce besoin. J'ai utilisé Mootools V1.4.5.

Classe PeriodicRequest

/**
 * Periodic request class
 *
 * @author gbretou
 */
var PeriodicRequest = new Class({
    Implements: Options,

    url : '',
    request: null,
    periodical: null,

    options: {
        method: 'GET',
        delay: '3000',
        onComplete: function(){},
        onCancel: function(){},
        onSuccess: function(){},
        onFailure: function(){}
    },

    /**
     * Constructor
     *
     * @param url
     * @param options
     */
    initialize: function(url, options)
    {
        this.setOptions(options);
        this.url     = url;
        this.method  = this.options.method;
        this.delay   = this.options.delay;
        this.request = new Request({
            method: this.method,
            url: this.url,
            onComplete: this.options.onComplete,
            onCancel: this.options.onCancel,
            onSuccess: this.options.onSuccess,
            onFailure: this.options.onFailure
        });
    },

    /**
     * Starts the timer
     */
    startTimer: function()
    {
        this.periodical = (function(){
            this.request.send();
        }.bind(this)).periodical(this.delay);
    },

    /**
     * Stops timer
     */
    stopTimer: function()
    {
        clearInterval(this.periodical);
    }
});

Utilisation

Le constructeur prend en paramètres 2 arguments :

  • url : la page à appeler,
  • data : un objet

L'objet data accepte les clés suivantes :

  • method : la méthode à utiliser (GET par défaut),
  • delay : le délai entre chaque requête (3000ms par défaut),
  • onComplete : callback lorsque la requête est terminée.

Dans le code suivant, nous allons créer une exécution périodique qui va requêter la page test.html toutes les 2 secondes. On affichera en console le contenu de la réponse.

data = {
            delay: 2000,
            onComplete: function(content) {console.log(content);}
};
var periodic = new PeriodicRequest('test.html', data);

La construction de l'objet ne lance pas automatiquement les actions périodiques. Vous devrez utiliser la méthode startTimer() :

periodic.startTimer();

Si vous souhaitez arrêtez l'exécution périodique, vous pourrez utiliser la méthode stopTimer() :

periodic.stopTimer();

Tuesday, July 24 2012

[PHP] PHP Cli Progress Bar

Voici une des dernière librairie que je viens de développer. Il s'agit d'une progress bar en PHP pour une utilisation en CLI.

Récupérer les sources

Pour récupérer les sources, vous pouvez utiliser :

  • git

git clone https://github.com/guiguiboy/PHP-CLI-Progress-Bar.git

Puis ajouter les lignes au début de votre script :

<?php

require_once 'ProgressBar/Manager.php';

require_once 'ProgressBar/Registry.php';


  • composer

Ajouter les lignes dans votre composer.json

    "require": {
                "php": ">=5.3.0",
                "guiguiboy/php-cli-progress-bar": "*"

    },
    "minimum-stability": "dev",

puis

php composer.phar install


Utilisation


Quick start

Une fois les fichiers chargés, rien de plus simple :

$progressBar = new \ProgressBar\Manager(0, 10);

for ($i = 0; $i <= 10; $i++)
{

    $progressBar->update($i);
    sleep(1);
}

Le code ci dessus va créer une progress bar pour un traitement de 10 éléments. A chaque itération, il attend 1 seconde.

1/10 [===>----------------------------------------------] 10.00% 00:00:09


Le format d'affichage par défaut est : %current%/%max% [%bar%] %percent%% %eta% où

  • %current% correspond à l'élément actuel
  • %max% correspond à l'élément max
  • %bar% correspond à la progress bar
  • %percent% correspond au pourcentage d'avancement
  • %eta% correspond à une estimation du temps de traitement restant

Configuration


Format

Vous pouvez changer le format de la progress bar avec la méthode setFormat :

$progressBar->setFormat('%current% |%bar%| %max%');


Longueur

La longueur se spécifie au niveau du constructeur. PAr défaut elle est de 80 caractères maximum. La taille de la progress bar se base sur cette information. PAr exemple :

$pb = new \ProgressBar\Manager(0, 20, 120);

Affichera :

1/20 [====>----------------------------------------------------------------------------------------] 5.00% 00:00:00


Caractères de la progress bar

Par défaut la progress bar utilisera les caractères suivants :

  • > : position courante
  • = : partie traitée
  • - : reste à faire

Ces caractères se configurent à l'initialisation. Par exemple :

$pb = new \ProgressBar\Manager(0, 20, 120, '-', ' ', ')');
$pb->update(5);

Affichera :

5/20 [-----------------------)                                                                    ] 25.00% 00:00:00


Extension


Ajouter des règles de remplacement


Vous pouvez ajouter des règles de remplacement : 

$pb = new Manager(0, 213);
$pb->setFormat('Progress : %current%/%max% [%bar%] %foo%');
$pb->addReplacementRule('%foo%', 70, function ($buffer, $registry) {return 'OK!';});
$pb->update(1);

Affichera :

Progress : 1/213 [>---------------------------------------------------] OK!


NB : Cette documentation ne sera pas forcément tenue à jour. Pour la version la plus récente, veuillez consulter le README.md du projet.

Tuesday, June 5 2012

Forum PHP 2012 organisé par l'AFUP : les slides des talks des conférenciers

Vous n'avez pas pu assister au Forum PHP 2012 ? Séance de rattrapage avec les slides des conférenciers :

PHP in 2012 : http://talks.php.net/show/afup12

Annotating with annotations : http://www.slideshare.net/rdohms/annotating-with-annotations-forumphp-2012

Coup de pied dans la LAMP : http://ternel.net/forumphp/Slideshow/#/author-bros

Anatomie du test : http://joind.in/talk/view/6440

Monitoring applicatif : http://joind.in/talk/view/6442

Anatomie, fonctionnement et performances de PHP : http://www.slideshare.net/jpauli/anatomie-et-performances-de-php

Lightning talk : Hip Hop for PHP : http://www.slideshare.net/gplessis/lightning-talk-hiphop-for-php

Gestion des dépendances dans un projet PHP : http://joind.in/talk/view/6458

Varnish pour les développeurs PHP : http://jrenard.info/blog/varnish-for-php-developers-the-slides.html

Drupal comme vous ne l'avez jamais vu : https://speakerdeck.com/u/gagarine/p/drupal-comme-vous-ne-lavez-jamais-vu

La qualité au delà du code : http://joind.in/talk/view/6454

Maitriser structures de données PHP 102 : http://www.slideshare.net/patrick.allaert/maitriser-les-structures-de-donnes-php-102-forum-paris-2012

Démons en PHP de inetd à ZeroMQ : http://www.slideshare.net/geekcto/dmons-en-php-de-inetd-zeromq

Accès concurrents et scalabilité : http://joind.in/6461

TDD avec ATOUM : http://joind.in/talk/view/6463

Vous trouverez en fichier joint mes notes prises lors de la conférence.

[EDIT]

Voici les slides du Symfony Live qui avait lieu peu de temps après : https://gist.github.com/2890651

Saturday, March 10 2012

restaurant.michelin.fr en ligne !

Le site http://restaurant.michelin.fr/ est désormais en ligne. Vous pouvez désormais rechercher des restaurants et laisser des avis.

Le site B2B est disponible à l'adresse : http://pro.restaurant.michelin.fr/

Friday, January 6 2012

[PHP] Spécifier une connexion en utf-8 avec Doctrine DBAL

Lorsque vous utilisez Doctrine DBAL (sur un projet Silex par exemple), voici comment spécifier l'encodage de la base de données.

Ajoutez une classe étendue de DoctrineServiceProvider et surchargez la méthode register(). Vous devrez utiliser le système d'event.

Exemple pour une base de données Mysql



use Silex\Application;
use Doctrine\DBAL\Event\Listeners\MysqlSessionInit;

class DoctrineServiceProvider extends \Silex\Provider\DoctrineServiceProvider
{
  public function register(Application $app)
  {
      parent::register($app);
      $app['db.event_manager']->addEventSubscriber(new MysqlSessionInit('utf8','utf8_unicode_ci'));
  }
}

Notez qu'avec le système d'event, vous pourrez réaliser d'autres actions telles que la mise en place de Behaviors.

Tuesday, December 20 2011

[Java] Débuter avec le développement Android

Ayant reçu un Samsung GALAXY S II (en remplacement de mon HTC Touch HD qui a rendu l’âme), j'ai tout de suite accroché au système des applications disponibles sur l'Android Market. Pour aller plus loin que la simple utilisation, J'ai voulu regarder comment créer une application sous Android.

Comme le veux la coutume, impossible de passer à coté de l'éternel "Hello World" quand on débute avec une nouvelle technologie. Voici les différentes étapes que j'ai suivi pour faire fonctionner mon application sous Windows : 

Installation

Tout d'abord, vous devez vous assurer d'avoir le JDK. Vous pourrez le télécharger ici : http://www.oracle.com/technetwork/java/javase/downloads/index.html

Sélectionnez la version qui correspond à votre OS.

Ensuite, vous devrez télécharger le SDK Android ici : http://developer.android.com/sdk/index.html

Pour simplifier l'utilisation du SDK en ligne de commande, nous allons renseigner le chemin vers le répertoire tools du SDK dans le PATH. Sous Windows 7, démarrer > rechercher "paramètres systèmes avancés". Cliquer sur le bouton "Variables d'environnement". Puis, dans la variables système, changer la valeur de la variable PATH pour y ajouter le path vers le dossier tools du SDK.

Configuration

Dans notre cas, nous considérerons l'utilisation de l'IDE Eclipse. Pour installer les plugins nécessaire, il faut suivre la documentation ici : http://developer.android.com/sdk/eclipse-adt.html#downloading

Notre environnement est désormais prêt et nous allons pouvoir créer l'application;

Commencez par créer un nouveau projet Android dans eclipse. Un Clic droit dans le package explorer puis sélectionnez "New" puis "Project ...".

Sélectionnez "Android Project" puis Next.

Choisissez un nom au projet, nous l'appellerons "HelloAndroid". Pour le reste de cet écran, le paramétrage par défaut est suffisant. Cliquez sur "Next".

Choisissez ensuite le SDK Android dans la liste. On prendra pour cet example la version 2.3.3. Cliquez ensuite sur "Next".

Enfin, choisissez un nom pour le package "HelloWorldAndroid" puis "Finish"

Dans le dernier écran, vous devrez remplir les champs :

  1. Application name : nom de l'application. Dans notre exemple nous utiliserons "Hello Android"
  2. Pckage name : il s'agit du namespace du package. Dans notre exemple, nous utiliserons "com.example.helloandroid". Veuillez à bien respecter les règles de nommage de package java. Sinon, vous pourrez rencontrer l'erreur "Aplication package XXX must have a minimum of 2 segments"
  3. Create Activity : laissez cette case cochée. Cela va permettre la génération d'une classe étendue de Activity sur laquelle nous allons travailler.

Cliquez sur "Finish".

Le système va ensuite générer le projet.

Dans src/com.example.helloandroid/HelloAndroid.java remplacez le code par  :

package com.example.helloandroid;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class HelloAndroid extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        TextView tv = new TextView(this);
        tv.setText("Hello, Android");
        setContentView(tv);

    }
}

Astuce : sous eclipse, vous pouvez faire Ctrl Shift O pour importer les packages manquants.

Comme vous vous en doutez, l'idée est d'afficher "Hello, Android" sur l'écran.

Nous allons maintenant tester notre développement. Pour cela, nous allons utiliser un AVD.

Créer un AVD

AVD (pour Android Virtual Device) est un émulateur qui vous permet de choisir un type d'appareil compatible et de le configurer afin de tester votre application.
Nous allons donc créer un AVD pour vérifier que notre application fonctionne bien.

Pour créer un AVD, il faut commencer par installer de nouveaux packages.
Lancer l'utilitaire "SDK Manager" en tant qu'administrateur.
Puis cocher les packages correspondant aux différentes versions que vous souhaitez installer. Veuillez à bien sélectionner le SDK Android 2.3.3 car c'est celui ci que nous utiliserons pour tester notre application Hello world.

Cliquez ensuite sur "Install"
Notez l'emplacement du téléchargement.

Il faudra ensuite enregistrer le bon path pour les SDK dans eclipse. Pour cela, dans eclipse, allez dans Window > Preference > Android.

Hebergement gratuit d'image et photo


Ensuite, cliquez sur Window > AVD Manager
Cliquez sur "New ...". Le système affiche une nouvelle fenêtre vous permettant de configurer votre AVD
  1. name (obligatoire) : nom de l'AVD.
  2. target (obligatoire) : version du SDK d'android. Sélectionnez 2.3.3

Pour le reste, le paramétrage par défaut est suffisant.


Tester l'application


Tester l'application est très simple. Sous eclipse, cliquez sur le projet à tester, puis Run > Run.
Sélectionnez "Android application"
Sélectionner une source de capture pour la vidéo, puis OK.

Le système va lancer le programme dans l'émulateur. Un peu de patience, cela peut prendre du temps...

Vous obtenez alors le tant attendu "Hello, Android" !

Hebergement gratuit d'image et photo


Sources :
http://ydisanto.developpez.com/tutoriels/android/debuter/
http://developer.android.com/resources/tutorials/hello-world.html

Thursday, September 29 2011

[Mysql] Mise à jour d'un mot de passe root de mysql oublié

Vous avez oublié le mot de passe root de mysql ? Pas de problème, il existe une solution pour cela.

Commencez par couper votre serveur mysql :

/etc/init.d/mysqld stop

Lancez la commande suivante :

/usr/bin/mysqld_safe --skip-grant-tables &


Cela permettra de lancer le serveur en arrière plan. L'option --skip-grant-tables vous permet de passer outre l'authentification.
Attention : vous ne pourrez toutefois pas créer d'utilisateur, ni modifier de droits dans ce mode.

Connectez vous en tant que root :

mysql -uroot mysql

mysql> update user SET Password=PASSWORD('MyNewPassword') Where User='root';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

mysql> exit;
Bye

Vous pouvez maintenant killer le processus lancé en arrière plan. Puis, relancez votre serveur mysql :

/etc/init.d/mysqld start

Vérifiez que votre identifiant a bien été pris en compte :

mysql -uroot -pMyNewPassword

C'est terminé !

Tuesday, July 26 2011

[sf2] Symfony 2 : c'est parti !

C'est annoncé sur le blog officiel de Symfony : la release stable 2.0 est sortie ce jour.

A cette occasion, plusieurs "launch parties" sont prévues pour permettre aux développeurs de se réunir pour fêter cet évènement.

Vous trouverez la liste des évènements ici.

Pour ma part, ayant déjà joué un peu avec la béta, je vais préparer un nouveau projet et je posterai différents articles sur son utilisation.

Wednesday, July 13 2011

[Bash] Remplacement de caractères de retour à la ligne par des espaces

Supposons que vous ayez la liste suivante :

gbretou@gunix:~$ cat test.txt
aaa
bbb
ccc
ddd

Et que vous voulez un résultat sur une ligne, vous pouvez utiliser tr pour convertir vos sauts de ligne en espace simple.

gbretou@gunix:~$ cat test.txt | tr '
' ' '
aaa bbb ccc ddd ati@gm21:~$

Si vous avez un svn st long comme le bras et que vous commitez en ligne de commande :

svn st | sed 's/^[AM]//g' | tr '
' ' ' | xargs svn ci -m'My super fun commit message'

Si vous voulez éviter des fichiers, pensez au grep -v après le svn st ;)

- page 1 of 4