--- /dev/null
+#!/usr/bin/php5
+<?php
+
+// {{{ function showHelp()
+
+function showHelp($error = null) {
+ if ($error) {
+ echo 'Ligne de commande non-valide : ' . $error, "\n\n";
+ }
+ echo 'csv2sql.php -t table [-i source] [-r phpfile]', "\n\n";
+ echo 'options:', "\n";
+ echo ' -t table: table in which insertion is to be done', "\n";
+ echo ' -i source: CSV source file (stdin if not defined or if source is \'-\'', "\n";
+ echo ' -r phpfile: PHP file which define relations', "\n";
+}
+
+// }}}
+// {{{ function processArgs()
+
+function processArgs()
+{
+ global $sourceName, $table, $includedFile;
+ $opts = getopt('i:t:r:d:');
+ if ($opts['i'] == '-' || empty($opts['i'])) {
+ $sourceName = 'php://stdin';
+ } else {
+ $sourceName = $opts['i'];
+ }
+
+ if ($opts['r'] && !empty($opts['r'])) {
+ $includedFile = $opts['r'];
+ }
+
+ if (!$opts['t'] || empty($opts['t'])) {
+ showHelp('Table non définie');
+ exit;
+ }
+ $table = $opts['t'];
+}
+
+// }}}
+
+processArgs();
+require_once(dirname(__FILE__) . '/../classes/csvimporter.php');
+require_once(dirname(__FILE__) . '/../classes/xdb.php');
+
+$source = file_get_contents($sourceName);
+$insert_relation = null;
+$update_relation = null;
+$debug = false;
+$action = CSV_INSERT;
+if (isset($includedFile)) {
+ require_once($includedFile);
+}
+
+$translater = new CSVImporter($table, $key, !$debug);
+$translater->setCSV($source);
+$translater->run($action, $insert_relation, $update_relation);
+
+?>
--- /dev/null
+<?php
+
+define('CSV_INSERT', 'insert'); // INSERT IGNORE
+define('CSV_REPLACE', 'replace'); // REPLACE
+define('CSV_UPDATE', 'update'); // INSERT and UPDATE on error
+
+class CSVImporter
+{
+ private $table;
+ private $key;
+ private $do_sql;
+
+ private $index;
+ private $separator;
+ private $data = array();
+
+ private $user_functions = array();
+
+ public function CSVImporter($table, $key = 'id', $do_sql = true)
+ {
+ $this->table = $table;
+ $this->key = $key;
+ $this->do_sql = $do_sql;
+ }
+
+ private function processLine($line)
+ {
+ $array = split($this->separator, $line);
+ if (is_null($this->index)) {
+ $this->index = $array;
+ return true;
+ }
+
+ if (count($array) != count($this->index)) {
+ return false;
+ }
+ $assoc = array();
+ $i = 0;
+ foreach ($this->index as $key) {
+ $assoc[$key] = $array[$i];
+ $i++;
+ }
+ $this->data[] = $assoc;
+ return true;
+ }
+
+ private function makeAssoc($line, $relation)
+ {
+ $ops = array();
+ foreach ($relation as $key=>$ref) {
+ if (@array_key_exists($ref, $line)) {
+ $value = $line[$ref];
+ } elseif (is_callable($ref, false)) {
+ $value = call_user_func($ref, $line, $key);
+ } else {
+ $value = $ref;
+ }
+ if (is_null($value) || $value == 'NULL') {
+ $value = 'NULL';
+ }
+ $ops[$key] = $value;
+ }
+ return $ops;
+ }
+
+ private function makeRequestArgs($line, $relation)
+ {
+ $ops = array();
+ foreach ($relation as $key=>$ref) {
+ if (@array_key_exists($ref, $line)) {
+ $value = $line[$ref];
+ } elseif (is_callable($ref, false)) {
+ $value = call_user_func($ref, $line, $key);
+ } else {
+ $value = $ref;
+ }
+ if (is_null($value) || $value == 'NULL') {
+ $value = 'NULL';
+ } else {
+ $value = "'" . addslashes($value) . "'";
+ }
+ $ops[$key] = "$key = $value";
+ }
+ return $ops;
+ }
+
+ private function makeRelation()
+ {
+ $relation = array();
+ foreach ($this->index as $title) {
+ $relation[$title] = $title;
+ }
+ return $relation;
+ }
+
+ private function execute($query)
+ {
+ if (!$this->do_sql) {
+ echo "$query;\n";
+ return false;
+ }
+ return XDB::execute($query);
+ }
+
+ private function getFieldList()
+ {
+ $res = XDB::query("SHOW COLUMNS FROM {$this->table}");
+ if ($res->numRows()) {
+ return $res->fetchColumn();
+ }
+ return null;
+ }
+
+ public function setCSV($csv, $index = null, $separator = ';')
+ {
+ $this->index = null;
+ $this->separator = $separator;
+ $csv = preg_split("/(\r\n|\r|\n)/", $csv);
+
+ foreach ($csv as $line) {
+ $this->processLine($line);
+ }
+ }
+
+ public function run($action = CSV_UPDATE, $insert_relation = null, $update_relation = null)
+ {
+ if (is_null($insert_relation)) {
+ $insert_relation = $this->makeRelation();
+ }
+ if (is_null($update_relation)) {
+ $update_relation = $insert_relation;
+ }
+ foreach ($this->data as $line) {
+ $set = join(', ', $this->makeRequestArgs($line, $insert_relation));
+ switch ($action) {
+ case CSV_INSERT:
+ $this->execute("INSERT IGNORE INTO {$this->table} SET $set");
+ break;
+ case CSV_REPLACE:
+ $this->execute("REPLACE INTO {$this->table} SET $set");
+ break;
+ case CSV_UPDATE:
+ if (!$this->execute("INSERT INTO {$this->table} SET $set")) {
+ $ops = $this->makeRequestArgs($line, $update_relation);
+ $set = join(', ', $ops);
+ $this->execute("UPDATE {$this->table} SET $set WHERE {$ops[$this->key]}");
+ }
+ break;
+ }
+ }
+ }
+
+ static public function dynamicCond($line, $key)
+ {
+ static $fields, $conds, $values, $thens, $elses;
+
+ if (!isset($fields)) {
+ $fields = Env::v('csv_cond_field');
+ $conds = Env::v('csv_cond');
+ $values = Env::v('csv_cond_value');
+ $thens = Env::v('csv_cond_then');
+ $elses = Env::v('csv_cond_else');
+ }
+ $field = $line[$fields[$key]];
+ $cond = $conds[$key];
+ $value = $values[$key];
+ if (is_numeric($field) && is_numeric($value)) {
+ $field = floatval($field);
+ $value = floatval($value);
+ }
+ switch ($cond) {
+ case 'defined': $ok = (!empty($field)); break;
+ case 'equals': $ok = ($field == $value); break;
+ case 'contains': $ok = (strpos($field, $value) !== false); break;
+ case 'contained': $ok = (strpos($value, $field) !== false); break;
+ case 'greater': $ok = ($field > $value); break;
+ case 'greater_or_equal': $ok ($field >= $value); break;
+ case 'lower': $ok = ($field < $value); break;
+ case 'lower_or_equal': $ok = ($field <= $value); break;
+ default: $ok = false;
+ }
+ if ($ok) {
+ return $thens[$key];
+ } else {
+ return $elses[$key];
+ }
+ }
+
+ public function registerFunction($name, $desc, $callback)
+ {
+ if (is_callable($callback)) {
+ $this->user_functions['func_' . $name] = array('desc' => $desc, 'callback' => $callback);
+ return true;
+ }
+ return false;
+ }
+
+ /** Handle insertion form
+ * @param $page PlatalPage to process
+ * @param $url URI of the page
+ * @param $field Editable fields
+ */
+ public function apply(&$page, $url, $fields = null)
+ {
+ if (is_null($fields)) {
+ $fields = $this->getFieldList();
+ }
+ if (is_null($fields)) {
+ return false;
+ }
+
+ $current = Env::v('csv_page');
+ if (empty($current)) {
+ $current = 'source';
+ }
+ $next = Env::v('csv_next_page');
+ if (empty($next)) {
+ $next = $current;
+ }
+ $csv = Env::v('csv');
+ if ($current == 'source' && Env::has('csv_valid')) {
+ $csv = Env::v('csv_source');
+ $next = 'values';
+ }
+ if ($csv) {
+ $this->setCSV($csv);
+ }
+ if ($current == 'values' && Env::has('csv_valid')) {
+ $next = 'valid';
+ }
+ if (empty($csv)) {
+ $next = 'source';
+ }
+ if ($next == 'valid') {
+ $insert = Env::v('csv_value');
+ $values = Env::v('csv_user_value');
+ $update = Env::v('csv_update');
+ foreach ($insert as $key=>$value) {
+ if (empty($value)) {
+ $insert[$key] = null;
+ } elseif ($value == 'user_value') {
+ $insert[$key] = $values[$key];
+ } elseif ($value == 'cond_value') {
+ $insert[$key] = array($this, 'dynamicCond');
+ } elseif (array_key_exists($value, $this->user_functions)) {
+ $insert[$key] = $this->user_functions[$value]['callback'];
+ }
+ if (isset($update[$key])) {
+ $update[$key] = $insert[$key];
+ }
+ }
+ if ($current == 'valid' && Env::has('csv_valid')) {
+ $this->run(Env::v('csv_action'), $insert, $update);
+ $page->assign('csv_done', true);
+ } else {
+ $preview = array();
+ foreach ($this->data as $line) {
+ $preview[] = $this->makeAssoc($line, $insert);
+ }
+ $page->assign('csv_preview', $preview);
+ }
+ }
+ $page->assign('csv_index', $this->index);
+ $page->assign('csv_funtions', $this->user_functions);
+ $page->assign('csv_page', $next);
+ $page->assign('csv_path', $url);
+ $page->assign('csv_fields', $fields);
+ $page->assign('csv', $csv);
+ }
+}
+
+?>
--- /dev/null
+{**************************************************************************}
+{* *}
+{* Copyright (C) 2003-2006 Polytechnique.org *}
+{* http://opensource.polytechnique.org/ *}
+{* *}
+{* This program is free software; you can redistribute it and/or modify *}
+{* it under the terms of the GNU General Public License as published by *}
+{* the Free Software Foundation; either version 2 of the License, or *}
+{* (at your option) any later version. *}
+{* *}
+{* This program is distributed in the hope that it will be useful, *}
+{* but WITHOUT ANY WARRANTY; without even the implied warranty of *}
+{* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *}
+{* GNU General Public License for more details. *}
+{* *}
+{* You should have received a copy of the GNU General Public License *}
+{* along with this program; if not, write to the Free Software *}
+{* Foundation, Inc., *}
+{* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *}
+{* *}
+{**************************************************************************}
+
+<script type="text/javascript">//<![CDATA[
+{literal}
+ function showValue(key, box)
+ {
+ var span_value = document.getElementById('csv_user_value_span[' + key + ']');
+ var span_cond = document.getElementById('csv_cond_value_span[' + key + ']');
+ var i = box.selectedIndex;
+ if (box.options[i].value == "user_value") {
+ span_value.style.display = "";
+ span_cond.style.display = "none";
+ } else if(box.options[i].value == "cond_value") {
+ span_value.style.display = "none";
+ span_cond.style.display = "";
+ } else {
+ span_value.style.display = "none";
+ span_conf.style.display = "none";
+ }
+ }
+ function showCond(key, box)
+ {
+ var line = document.getElementById('csv_cond_value[' + key + ']');
+ var i = box.selectedIndex;
+ if (box.options[i].value == "defined") {
+ line.style.display = "none";
+ } else {
+ line.style.display = "";
+ }
+ }
+ function gotoPage(page)
+ {
+ document.getElementById('csv_next_page').value = page;
+ document.getElementById('csv_form').submit();
+ return false;
+ }
+{/literal}
+//]]></script>
+<form action="{$csv_path}" method="post" id="csv_form">
+<table class="cadre_a_onglet" cellpadding="0" cellspacing="0" style="width: 98%; margin-left:1%;">
+ <tr>
+ <td>
+ <ul id="onglet">
+ {if $csv_page eq 'source'}
+ <li class="actif">1 - Choisir<br />la source</li>
+ {else}
+ <li><a href="{$csv_path}" onclick="return gotoPage('source');">1 - Choisir<br />la source</a></li>
+ {/if}
+ {if $csv_page eq 'values'}
+ <li class="actif">2 - Définir<br />les valeurs</li>
+ {elseif $csv}
+ <li><a href="{$csv_path}" onclick="return gotoPage('values');">2 - Définir<br />les valeurs</a></li>
+ {else}
+ <li>2 - Définir<br />les valeurs</li>
+ {/if}
+ {if $csv_page eq 'valid'}
+ <li class="actif">3 - Vérifier<br />et valider</li>
+ {elseif $csv_action}
+ <li><a href="{$csv_path}" onclick="return gotoPage('valid');">3 - Vérifier<br />et valider</a></li>
+ {else}
+ <li>3 - Vérifier<br />et valider</li>
+ {/if}
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td class="conteneur_tab">
+ <table style="width: 100%">
+ <tr>
+ <td>
+ {if $csv_page eq 'source'}
+ <textarea name="csv_source" rows="20" cols="80">{$csv|default:$smarty.request.csv_source}</textarea><br />
+ Entrez les données sous la forme :<br />
+ <pre class="center">TITRE1;TITRE2;...
+val1_1;val1_2;...
+val2_1;val2_2;...
+val3_1;val3_2;...</pre>
+ {elseif $csv_page eq 'values'}
+ <div class="center">
+ Action à effectuer si l'entrée existe :
+ <select name="csv_action" onchange="this.form.submit()">
+ <option value="insert" {if $smarty.request.csv_action eq 'insert'}selected="selected"{/if}>
+ ne rien faire
+ </option>
+ <option value="replace" {if $smarty.request.csv_action eq 'replace'}selected="selected"{/if}>
+ remplacer par la nouvelle entrée
+ </option>
+ <option value="update" {if $smarty.request.csv_action eq 'update'}selected="selected"{/if}>
+ mettre à jour les champs sélectionnés
+ </option>
+ </select>
+ </div>
+ <table class="bicol">
+ <tr>
+ <th>Champ</th>
+ <th colspan="2">Valeur</th>
+ {if $smarty.request.csv_action eq 'update'}
+ <th>MàJ</th>
+ {/if}
+ </tr>
+ {foreach from=$csv_fields item=f}
+ <tr class="{cycle values="pair,impair"}">
+ <td>{$f}</td>
+ <td>
+ <select name="csv_value[{$f}]" onchange="showValue('{$f}', this);">
+ <option value="" {if !$smarty.request.csv_value[$f]}selected="selected"{/if}>
+ Vide
+ </option>
+ <option value="user_value" {if $smarty.request.csv_value[$f] eq "user_value"}selected="selected"{/if}>
+ Entrer la valeur
+ </option>
+ <option value="cond_value" {if $smarty.request.csv_value[$f] eq "cond_value"}selected="selected"{/if}>
+ Valeur conditionnelle
+ </option>
+ <optgroup label="Colonnes du CSV">
+ {foreach from=$csv_index item=col}
+ <option value="{$col}" {if $smarty.request.csv_value[$f] eq $col}selected="selected"{/if}>{$col}</option>
+ {/foreach}
+ </optgroup>
+ {if $csv_functions|count}
+ <optgroup label="Fonctions">
+ {foreach from=$csv_functions key=func item=desc}
+ <option value="{$func}" {if $smarty.request.csv_value[$f] eq $func}selected="selected"{/if}>{$desc.desc}</option>
+ {/foreach}
+ </optgroup>
+ {/if}
+ </select>
+ </td>
+ <td>
+ <span id="csv_user_value_span[{$f}]" {if $smarty.request.csv_value[$f] neq "user_value"}style="display: none"{/if}>
+ <input type="text" name="csv_user_value[{$f}]" value="{$smarty.request.csv_user_value[$f]}" />
+ </span>
+ <span id="csv_cond_value_span[{$f}]" {if $smarty.request.csv_value[$f] neq "cond_value"}style="display: none"{/if}>
+ Si
+ <select name="csv_cond_field[{$f}]">
+ {foreach from=$csv_index item=col}
+ <option value="{$col}" {if $smarty.request.csv_cond_field_value[$f] eq $col}selected="selected"{/if}>
+ {$col}
+ </option>
+ {/foreach}
+ </select>
+ <select name="csv_cond[{$f}]" onchange="showCond('{$f}', this)">
+ <option value="defined" {if $smarty.request.csv_cond[$f] eq "defined"}selected="selected"{/if}>
+ défini
+ </option>
+ <option value="equals" {if $smarty.request.csv_cond[$f] eq "equals"}selected="selected"{/if}>
+ est égale à
+ </option>
+ <option value="contains" {if $smarty.request.csv_cond[$f] eq "contains"}selected="selected"{/if}>
+ contient
+ </option>
+ <option value="contained" {if $smarty.request.csv_cond[$f] eq "contained"}selected="selected"{/if}>
+ est contenu dans
+ </option>
+ <option value="greater" {if $smarty.request.csv_cond[$f] eq "greater"}selected="selected"{/if}>
+ supérieur à
+ </option>
+ <option value="greater_or_equal" {if $smarty.request.csv_cond[$f] eq "greater_or_equal"}selected="selected"{/if}>
+ supérieur ou égal à
+ </option>
+ <option value="lower" {if $smarty.request.csv_cond[$f] eq "lower"}selected="selected"{/if}>
+ inférieur à
+ </option>
+ <option value="lower_or_equal" {if $smarty.request.csv_cond[$f] eq "lower_or_equal"}selected="selected"{/if}>
+ inférieur ou égal à
+ </option>
+ </select>
+ <span id="csv_cond_value[{$f}]" {if $smarty.request.csv_cond[$f] eq "defined" || !$smarty.request.csv_cond[$f]}style="display: none"{/if}>
+ <input type="text" name="csv_cond_value[{$f}]" value="{$smarty.request.csv_cond_value[$f]}" />
+ </span>
+ <br />Alors <input type="text" name="csv_cond_then[{$f}]" value="{$smarty.request.csv_cond_then[$f]}" />
+ <br />Sinon <input type="text" name="csv_cond_else[{$f}]" value="{$smarty.request.csv_cond_else[$f]}" />
+ </span>
+ </td>
+ {if $smarty.request.csv_action eq 'update'}
+ <td class="center">
+ <input type="checkbox" name="csv_update[{$f}]" {if $smarty.request.csv_update[$f]}checked="checked"{/if} />
+ </td>
+ {/if}
+ </tr>
+ {/foreach}
+ </table>
+ {elseif $csv_page eq 'valid'}
+ {if !$csv_done}
+ <table class="bicol">
+ <tr>
+ {foreach from=$csv_fields item=f}
+ <th>{$f}</th>
+ {/foreach}
+ </tr>
+ {foreach from=$csv_preview item=assoc}
+ <tr class="{cycle values="pair,impair"}">
+ {foreach from=$csv_fields item=f}
+ <td>{$assoc[$f]}</td>
+ {/foreach}
+ <tr>
+ {/foreach}
+ </table>
+ {else}
+ Les données ont été ajoutées.
+ {/if}
+ {/if}
+ </td>
+ </tr>
+
+ {if !$csv_done}
+ <tr>
+ <td class="center">
+ <input type="hidden" name="csv_page" value="{$csv_page}" />
+ <input type="hidden" id="csv_next_page" name="csv_next_page" value="{$csv_page}" />
+ <input type="hidden" name="csv" value="{$csv}" />
+ {if $csv_page neq 'values'}
+ <input type="hidden" name="csv_action" value="{$smarty.request.csv_action}" />
+ {foreach from=$csv_fields item=f}
+ <input type="hidden" name="csv_value[{$f}]" value="{$smarty.request.csv_value[$f]}" />
+ <input type="hidden" name="csv_user_value[{$f}]" value="{$smarty.request.csv_user_value[$f]}" />
+ <input type="hidden" name="csv_cond_field[{$f}]" value="{$smarty.request.csv_cond_field[$f]}" />
+ <input type="hidden" name="csv_cond[{$f}]" value="{$smarty.request.csv_cond[$f]}" />
+ <input type="hidden" name="csv_cond_value[{$f}]" value="{$smarty.request.csv_cond_value[$f]}" />
+ <input type="hidden" name="csv_cond_then[{$f}]" value="{$smarty.request.csv_cond_then[$f]}" />
+ <input type="hidden" name="csv_cond_else[{$f}]" value="{$smarty.request.csv_cond_else[$f]}" />
+ <input type="hidden" name="csv_update[{$f}]" value="{$smarty.request.csv_update[$f]}" />
+ {/foreach}
+ {/if}
+ {if $csv_page eq 'source'}
+ <input type="submit" name="csv_valid" value="Changer le CSV" />
+ {elseif $csv_page eq 'values'}
+ <input type="submit" name="csv_valid" value="Aperçu" />
+ {elseif $csv_page eq 'valid'}
+ <input type="submit" name="csv_valid" value="Valider" />
+ {/if}
+ </td>
+ </tr>
+ {/if}
+ </table>
+ </td>
+ </tr>
+</table>
+</form>
+
+{* vim:set et sws=2 sts=2 sw=2: *}