Publié le 26 Février 2013

Il faut d'abord télécharger le fichier à l'aide d'un formulaire HTML.

Ensuite il faut récupérer le fichier avec du PHP et l'enregistrer dans un dossier.

Après il y a une commande MySQL qui permet de charger directement le contenu d'un fichier dans une table sans effectuer des INSERT:

LOAD DATA INFILE 'monfichier.csv' INTO TABLE ma_table fields terminated by ';';

Si tous les champs ne sont pas présent on peut éventuellement rajouter la liste des champs entre parenthèses à la fin de la requête.

Sous Ubuntu il y a qq soucis de sécurité car le process mysqld est surveillé par apparmor. MySQL se plaindra de ne pas trouver le fichier importé:

ERROR 13 (HY000): Can't get stat of '/root/api.csv' (Errcode: 13)

Pour le vérifier il faut utiliser:

sudo aa-status

5 processes are in enforce mode.
   /sbin/dhclient (2203)
   /usr/bin/evince (3641)
   /usr/lib/telepathy/mission-control-5 (2911)
   /usr/sbin/cupsd (1066)
   /usr/sbin/mysqld (6970) 

MySQL est bien en 'enforce' mode. Il faut donc modifier la config apparmor pour donner acces en lecture aux fichiers importés pour mysql:

sudo vi /etc/apparmor.d/usr.sbin.mysqld

Ensuite il faut ajouter 2 lignes à la fin du fichier (avant l'accolade de fermeture)

 /var/www/mon_site/import/ r,
 /var/www/mon_site/import/* r,

Bien sûr /var/www/mon_site/import est le dossier dans lequel j'enregistre les fichiers CSV téléchargés.

Ensuite il faut recharger la config d'apparmor:

sudo /etc/init.d/apparmor reload

Maintenant le LOAD DATA INFILE devrait fonctionner sinon il faut vérifier les privilèges mysql.

Par exemple l'erreur:

ERROR 1045 (28000): Access denied for user

se résout en ajoutant le privilège "FILE" avec la commande suivante:

GRANT FILE ON *.* TO 'my_user'@'localhost';

Dans les versions précédentes de MySQL il était possible de contourner le problème en utilisant un LOAD DATA LOCAL INFILE mais désormais cette option est désactivé par défaut. Il faut préciser --local-infile=0 sur la ligne de commande pour démarrer mysql.

LOAD DATA INFILE signifie que le fichier à charger se trouve sur le serveur MySQL.

LOAD DATA LOCAL INFILE signifie que le fichier se trouve du côté du client MySQL et que c'est ce dernier qui l'enverra au serveur.

Pour ma part PHP et MySQL tournent sur la même machine mais attention si ce n'est pas le cas.

Voir les commentaires

Rédigé par Bliz

Publié dans #MySQL

Repost 0

Publié le 21 Février 2013

la commande 'date' unix permet d'afficher/fixer la date courante mais on peut aussi préciser le format de la date.

Les différents tags disponibles sont détaillées dans le man:

man date

Sinon pour récupérer la date au format SQL:

date "+%Y-%m-%d %H:%M:%S"

Si on ne veut pas afficher la date courante on peut utiliser l'option -d pour préciser une autre date:

date -d yesterday "+%Y-%m-%d"

Voir les commentaires

Rédigé par Bliz

Publié dans #Script

Repost 0

Publié le 16 Février 2013

Je me suis lancé dans le tutorial AngularJS (très bien fait par ailleurs) mais voilà sous ubuntu j'ai rencontré quelques problèmes.

Pas avec Angular directement mais dans l'installation de l'environnement.

Tout d'abord il faut installer nodeJS. Et bien justement il existe un package nodejs ubuntu seulement il installe un executable nommé nodejs alors que testacular (le framework de test cherche un "node").

J'ai renommé nodejs en node mais ça ne passe toujours pas! Et oui, le package Ubuntu est une ancienne version de nodejs (0.6.x) alors qu'il faut une 0.8.x.

J'ai laissé tomber les packages et j'ai installé node depuis le code source:

sudo git clone git://github.com/joyent/node.git

cd node

git checkout v0.8.20

sudo ./configure

sudo make

sudo make install 

Voilà node est installé avec un binaire nommé "node". Parfait mais Testacular ne parvient toujours pas à exécuter les tests car il n'arrive pas à démarrer chrome.

Sous ubuntu chrome se lance avec la commande: 

/usr/bin/chromium-browser

Il faut donc renseigned la variable d'environnement CHROME_BIN pour indiquer comment lancer chrome:

export CHROME_BIN=/usr/bin/chromium-browser

Enfin, les tests passent!

Voir les commentaires

Rédigé par Bliz

Publié dans #Linux

Repost 0

Publié le 13 Février 2013

Pour faire un dump SVN on utilise normalement la commande :

svnadmin dump /var/svn/repos > repos.dump

Le problème est que svnadmin dump ne fonctionne qu'en local mais il existe une solution pour faire un dump à distance en utilisant:

svnrdump dump http://server/repos/projet > projet.dump

La documentation sur svnrdump se trouve dans le SVN book : http://svnbook.red-bean.com/en/1.7/svn.ref.svnrdump.html.

Voir les commentaires

Rédigé par Bliz

Publié dans #Version control

Repost 0

Publié le 8 Février 2013

Dans GWT pour créer de nouveaux widgets il est d'usage d'étendre la classe Composite. Je n'ai pas rencontré de problème pour créer les widgets par contre pour générer des évènements lors d'un changement de valeur dans le widget ça n'a pas été aussi simple.

J'ai opté pour une solution utilisant les ValueChangeEvent. L'implémentation est assez simple mais c'est surtout le manque de documentation qui pêche.

Voilà comment faire un composite qui génère des ValueChangeEvent:

 

public class DateTimePicker extends Composite implements HasValueChangeHandlers<Date>{

   private final HorizontalPanel content = new HorizontalPanel();
   private final DateBox dateBox = new DateBox();
   private final ListBox timeListBox = new ListBox();

   public DateTimePicker(){
      dateBox.setFormat(new DefaultFormat(DateTimeFormat.getFormat("yyyy-MM-dd")));
      content.add(dateBox);
      content.add(timeListBox);
      initWidget(content);
      registerHandlers();
      fillInTimeListBox();
   }

   private void registerHandlers(){
      // On enregistre des handler pour être notifié des changements dans nos composants
      dateBox.addValueChangeHandler(new ValueChangeHandler<Date>() {
         @Override
         public void onValueChange(ValueChangeEvent<Date> arg0) {
            DateTimePicker.this.onValueChange();
         }
      });
      timeListBox.addChangeHandler(new ChangeHandler() {
         @Override
         public void onChange(ChangeEvent arg0) {
            DateTimePicker.this.onValueChange();
         }
      });
   }

   private void fillInTimeListBox(){
      NumberFormat format = NumberFormat.getFormat("00");
      for(int i = 0; i < 24; i++){
         timeListBox.addItem(format.format(i)+":00"); 
      }
   }

   public Date getValue(){
      String date = dateBox.getTextBox().getText();
      if(date != null && !date.isEmpty()){
         String time = timeListBox.getValue(timeListBox.getSelectedIndex());
         Date value = DateTimeFormat.getFormat("yyyy-MM-dd HH:mm").parse(date+" "+time);
         return value;
      }
      return null;
   }

   @Override
   public HandlerRegistration addValueChangeHandler(ValueChangeHandler<Date> handler) {
      // permet à d'autres objets de s'enregistrer pour recevoir des ValueChangeEvents
      return addHandler(handler, ValueChangeEvent.getType());
   }

   private void onValueChange(){
      // lance l'évènement, appelé lors des changements dans la dateBox ou la ListBox
      ValueChangeEvent.fire(this, getValue());
   }
}   

Voir les commentaires

Rédigé par Bliz

Publié dans #GWT

Repost 0