Page MenuHomeDevCentral

No OneTemporary

diff --git a/includes/core.php b/includes/core.php
index c00af3a..6f2aec4 100755
--- a/includes/core.php
+++ b/includes/core.php
@@ -1,345 +1,345 @@
<?php
/*
* Keruald, core libraries for Pluton and Xen engines.
* (c) 2010, Sébastien Santoro aka Dereckson, some rights reserved
* Released under BSD license
*
* Core
*
* 0.1 2010-02-27 2:04 DcK
*/
////////////////////////////////////////////////////////////////////////////////
/// ///
/// Configures PHP and loads site-wide used libraries ///
/// ///
////////////////////////////////////////////////////////////////////////////////
//Disables register globals
ini_set('register_globals', 'off');
//Reports all errors, help notices (including STRICT in PHP 6)
error_reporting(E_ALL & ~E_NOTICE);
//Load libraries
include_once("config.php"); //Site config
include_once("error.php"); //Error management
include_once("mysql.php"); //MySQL layer
include_once("session.php"); //Sessions handler
////////////////////////////////////////////////////////////////////////////////
/// ///
/// Information helper functions ///
/// ///
////////////////////////////////////////////////////////////////////////////////
/*
* Gets the username matching specified user id
* @param string $user_id the user ID
* @return string the username
*/
function get_username ($user_id) {
global $db;
$user_id = $db->sql_escape($user_id);
$sql = 'SELECT username FROM '. TABLE_USERS . " WHERE user_id = '$userid'";
return $db->sql_query_express($sql, "Can't get username from specified user id");
}
/*
* Gets the user id matching specified username
* @param string $username the username
* @return string the user ID
*/
function get_userid ($username) {
global $db;
$username = $db->sql_escape($username);
$sql = 'SELECT user_id FROM '. TABLE_USERS . " WHERE username LIKE '$username'";
return $db->sql_query_express($sql, "Can't get user id from specified username");
}
////////////////////////////////////////////////////////////////////////////////
/// ///
/// Misc helper functions ///
/// ///
////////////////////////////////////////////////////////////////////////////////
//Plural management
/*
* Gets a "s" if the specified amount requests the plural
* @param mixed $amount the quantity (should be numeric)
* @return string 's' if the amount is greater or equal than 2 ; otherwise, ''
*/
function s ($amount) {
if ($amount >= 2 || $amount <= -2 ) return 's';
}
/*
* Prints human-readable information about a variable, wrapped in a <pre> block
* @param mixed $mixed the variable to dump
*/
function dprint_r ($mixed) {
echo '<pre>';
print_r($mixed);
echo '</pre>';
}
/*
* Generates a new GUID
* @return string a guid (without {})
*/
function new_guid () {
//The guid chars
$chars = explode(',', 'a,b,c,d,e,f,0,1,2,3,4,5,6,7,8,9');
//Let's build our 36 characters string
//e.g. 68ed40c6-f5bb-4a4a-8659-3adf23536b75
$guid = "";
for ($i = 0 ; $i < 36 ; $i++) {
if ($i == 8 || $i == 13 || $i == 18 || $i == 23) {
//Dashes at position 9, 14, 19 and 24
$guid .= "-";
} else {
//0-f hex digit elsewhere
$guid .= $chars[mt_rand() % sizeof($characters)];
}
}
return $guid;
}
/*
* Determines if the expression is a valid guid (in uuid notation, without {})
* @param string $expression the guid to check
* @return true if the expression is a valid guid ; otherwise, false
*/
function is_guid ($expression) {
//We avoid regexp to speed up the check
//A guid is a 36 characters string
if (strlen($expression) != 36) return false;
$expression = strtolower($expression);
for ($i = 0 ; $i < 36 ; $i++) {
if ($i == 8 || $i == 13 || $i == 18 || $i == 23) {
//with dashes
if ($expression[$i] != '-') return false;
} else {
//and hex numbers
if (!is_numeric($expression[$i]) && $expression[$i] != 'a' && $expression[$i] != 'b' && $expression[$i] != 'c' && $expression[$i] != 'd' && $expression[$i] != 'e' && $expression[$i] != 'f' ) return false;
}
}
return true;
}
/*
* Gets file extension
* @param string $file the file to get the extension
*/
function get_extension ($file) {
$dotPosition = strrpos($file, ".");
return substr($file, $dotPosition + 1);
}
/**
* Determines if a string starts with specified substring
*
* @param string $haystack the string to check
* @param string $needle the substring to determines if it's the start
* @param boolean $case_sensitive determines if the search must be case sensitive
* @return boolean true if $haystack starts with $needle ; otherwise, false.
*/
function string_starts_with ($haystack, $needle, $case_sensitive = true) {
if (!$case_sensitive) {
$haystack = strtoupper($haystack);
$needle = strtoupper($needle);
}
if ($haystack == $needle) return true;
return strpos($haystack, $needle) === 0;
}
/**
* Gets the portion of the string between $includeFrom and $includeTo
*/
function string_between ($haystack, $from, $to, $includeFrom = false, $includeTo = false) {
//Gets start position
$pos1 = strpos($haystack, $from);
if ($pos1 === false) {
return "";
}
if (!$includeFrom) $pos1 += strlen($from);
//Gets end position
$pos2 = strpos($haystack, $to, $pos1 + strlen($from));
if ($pos2 === false) {
return substr($haystack, $pos1);
}
- if ($includeTo) $pos2 += strlen($includeTo);
+ if ($includeTo) $pos2 += strlen($to);
//Gets middle part
return substr($haystack, $pos1, $pos2 - $pos1);
}
////////////////////////////////////////////////////////////////////////////////
/// ///
/// URL helpers functions ///
/// ///
////////////////////////////////////////////////////////////////////////////////
/*
* Gets URL
* @return string URL
*/
function get_url () {
global $Config;
if (func_num_args() > 0) {
$pieces = func_get_args();
return $Config['BaseURL'] . '/' . implode('/', $pieces);
} elseif ($Config['BaseURL'] == "" || $Config['BaseURL'] == "/index.php") {
return "/";
} else {
return $Config['BaseURL'];
}
}
/*
* Gets page URL
* @return string URL
*/
function get_page_url () {
$url = $_SERVER['SCRIPT_NAME'] . $_SERVER['PATH_INFO'];
if (substr($url, -10) == "/index.php") {
return substr($url, 0, -9);
}
return $url;
}
/*
* Gets server URL
* @todo find a way to detect https:// on non standard port
* @return string the server URL
*/
function get_server_url () {
switch ($port = $_SERVER['SERVER_PORT']) {
case '80':
return "http://$_SERVER[SERVER_NAME]";
case '443':
return "https://$_SERVER[SERVER_NAME]";
default:
return "http://$_SERVER[SERVER_NAME]:$_SERVER[SERVER_PORT]";
}
}
/*
* Gets $_SERVER['PATH_INFO'] or computes the equivalent if not defined.
* @return string the relevant URL part
*/
function get_current_url () {
global $Config;
//Gets relevant URL part from relevant $_SERVER variables
if (array_key_exists('PATH_INFO', $_SERVER)) {
//Without mod_rewrite, and url like /index.php/controller
//we use PATH_INFO. It's the easiest case.
return $_SERVER["PATH_INFO"];
}
//In other cases, we'll need to get the relevant part of the URL
$current_url = get_server_url() . $_SERVER['REQUEST_URI'];
//Relevant URL part starts after the site URL
$len = strlen($Config['SiteURL']);
//We need to assert it's the correct site
if (substr($current_url, 0, $len) != $Config['SiteURL']) {
dieprint_r(GENERAL_ERROR, "Edit includes/config.php and specify the correct site URL<br /><strong>Current value:</strong> $Config[SiteURL]<br /><strong>Expected value:</strong> a string starting by " . get_server_url(), "Setup");
}
if (array_key_exists('REDIRECT_URL', $_SERVER)) {
//With mod_rewrite, we can use REDIRECT_URL
//We takes the end of the URL, ie *FROM* $len position
return substr(get_server_url() . $_SERVER["REDIRECT_URL"], $len);
}
//Last possibility: use REQUEST_URI, but remove QUERY_STRING
//If you need to edit here, use $_SERVER['REQUEST_URI']
//but you need to discard $_SERVER['QUERY_STRING']
//We takes the end of the URL, ie *FROM* $len position
$url = substr(get_server_url() . $_SERVER["REQUEST_URI"], $len);
//But if there are a query string (?action=... we need to discard it)
if ($_SERVER['QUERY_STRING']) {
return substr($url, 0, strlen($url) - strlen($_SERVER['QUERY_STRING']) - 1);
}
return $url;
}
/*
* Gets an array of url fragments to be processed by controller
* @return array an array containing URL fragments
*/
function get_current_url_fragments () {
$url_source = get_current_url();
if ($url_source == '/index.php') return array();
return explode('/', substr($url_source, 1));
}
/**
* Gets the URL for the specified resources
*
* @param ... string a arbitray number of path info
*/
function get_url_for () {
global $Config;
$url = get_server_url() . '/' . $Config[BaseURL];
if (func_num_args()) {
$url .= implode('/', func_get_args());
}
return $url;
}
////////////////////////////////////////////////////////////////////////////////
/// ///
/// URL xmlHttpRequest helpers functions ///
/// ///
////////////////////////////////////////////////////////////////////////////////
/*
* Gets an hash value to check the integrity of URLs in /do.php calls
* @param Array $args the args to compute the hash
* @return the hash paramater for your xmlHttpRequest url
*/
function get_xhr_hash ($args) {
global $Config;
array_shift($args);
return md5($_SESSION['ID'] . $Config['SecretKey'] . implode('', $args));
}
/*
* Gets the URL to call do.php, the xmlHttpRequest controller
* @return string the xmlHttpRequest url, with an integrity hash
*/
function get_xhr_hashed_url () {
global $Config;
$args = func_get_args();
$args[] = get_xhr_hash($args);
return $Config['DoURL'] . '/' . implode('/', $args);
}
/*
* Gets the URL to call do.php, the xmlHttpRequest controller
* @return string the xmlHttpRequest url
*/
function get_xhr_url () {
global $Config;
$args = func_get_args();
return $Config['DoURL'] . '/' .implode('/', $args);
}
diff --git a/includes/core2.php b/includes/core2.php
index abdc0ce..00252d5 100644
--- a/includes/core2.php
+++ b/includes/core2.php
@@ -1,13 +1,61 @@
<?php
function is_mail ($string) {
return preg_match('/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z0-9]{2,4}$/', $string);
}
/*
Unit testing ->
1 is_mail("dereckson@gmail.com");
1 is_mail("dereckson@trustspace.42");
1 is_mail("dereckson@gmail.a.a.a.a.a.a.a.ax.org");
1 is_mail("dereckson+wazza@gmail.com");
0 is_mail("dereckson`ls`@gmail.com");
-*/
\ No newline at end of file
+*/
+
+/**
+ * Gets an HTTP context
+ */
+function get_http_context () {
+ return stream_context_create([
+ 'http' => [
+ 'method' => 'GET',
+ 'user_agent' => 'NasqueronTools/0.1'
+ ]
+ ]);
+}
+
+function get_innerHtml (DOMNode $element) {
+ $innerHtml = "";
+
+ foreach ($element->childNodes as $childNode) {
+ $dom = new DOMDocument('1.0', 'utf-8');
+ $dom->appendChild(
+ $dom->importNode($childNode, true)
+ );
+ $innerHtml .= trim($dom->saveHTML());
+ }
+
+ return $innerHtml;
+}
+
+function get_array_from_html_table($html, $stripHTML = true) {
+ $array = [];
+
+ $html = str_ireplace('<th ', '<td ', $html);
+ $html = str_ireplace('<th>', '<td>', $html);
+ $html = str_ireplace('</th>', '</td>', $html);
+ $html = str_ireplace('<th/>', '<td/>', $html); //No reason not to be as permissive as browsers.
+
+ $dom = new DOMDocument('1.0', 'utf-8');
+ $dom->loadHTML($html);
+ $rows = $dom->getElementsByTagName('tr');
+ foreach ($rows as $row) {
+ $values = [];
+ $rowCells = $row->getElementsByTagName('td');
+ foreach ($rowCells as $cell) {
+ $values[] = $stripHTML ? $cell->nodeValue : get_innerHtml($cell);
+ }
+ $array[] = $values;
+ }
+ return $array;
+}
\ No newline at end of file
diff --git a/includes/mediawikibot.php b/includes/mediawikibot.php
new file mode 120000
index 0000000..7607632
--- /dev/null
+++ b/includes/mediawikibot.php
@@ -0,0 +1 @@
+/home/dereckson/dev/mediawikibot/mediawikibot.php
\ No newline at end of file
diff --git a/infographics/_documents.xml b/infographics/_documents.xml
new file mode 100644
index 0000000..0ab0028
--- /dev/null
+++ b/infographics/_documents.xml
@@ -0,0 +1,12 @@
+<documents topic="infographics">
+ <document>
+ <article>parlement-fr</article>
+ <title>Le parlement Français, une gérontocratie ?</title>
+ <description>Distribution par âge des sénateurs &amp; députés.</description>
+ <head><![CDATA[
+ <link href="/includes/kendo/styles/kendo.dataviz.min.css" rel="stylesheet">
+ <script src="/includes/kendo/js/jquery.min.js"></script>
+ <script src="/includes/kendo/js/kendo.dataviz.min.js"></script>
+ ]]></head>
+ </document>
+</documents>
\ No newline at end of file
diff --git a/infographics/datasources/datasource.php b/infographics/datasources/datasource.php
new file mode 100644
index 0000000..3e7ada4
--- /dev/null
+++ b/infographics/datasources/datasource.php
@@ -0,0 +1,9 @@
+<?php
+
+/**
+ * A source of data
+ */
+class DataSource {
+}
+
+?>
\ No newline at end of file
diff --git a/infographics/datasources/mediawikidatasources.php b/infographics/datasources/mediawikidatasources.php
new file mode 100644
index 0000000..24b6328
--- /dev/null
+++ b/infographics/datasources/mediawikidatasources.php
@@ -0,0 +1,158 @@
+<?php
+require_once('datasource.php');
+require_once('includes/mediawikibot.php');
+require_once('includes/cache/cache.php');
+
+/**
+ * A MediaWiki data source
+ *
+ * @todo Evaluate if it makes sense to split this class in two, one for wikitext parsing, one for HTML output parsing
+ */
+class MediaWikiDataSource extends DataSource {
+ /**
+ * The source reading mode: wiki to parse wikitext, html to parse HTML output
+ */
+ public $source_mode;
+
+ /**
+ * The name of the article (used in wiki source mode)
+ */
+ public $source_wiki;
+
+ /**
+ * The URL of the article (used in HTML source mode)
+ */
+ public $source_html;
+
+ /**
+ * The text of the article (wikitext in wiki source mode, raw HTML in HTML source mode)
+ */
+ public $source_data;
+
+ /**
+ * The API entry point URL (e.g. http://www.mediawiki.org/w/api.php)
+ */
+ public $api_url;
+
+ /**
+ * Initializes a new instance of the MediaWikiDataSource class
+ *
+ * @param $source The source target, article title in wiki mode, article URL in html mode
+ * @param $mode The source mode (facultative, by default 'wiki')
+ */
+ public function __construct ($source = false, $mode = 'wiki') {
+ $this->source_mode = $mode;
+ if ($source !== false) {
+ switch ($mode) {
+ case 'wiki': $this->source_wiki = $source; break;
+ case 'html': $this->source_html = $source; break;
+ default: throw new Exception("Unknown source mode: $mode.");
+ }
+ }
+ }
+
+ /**
+ * Gets the general purpose MediaWiki entry point (e.g. http://www.mediawiki.org/w/index.php)
+ *
+ * @return string The MediaWiki entry point
+ *
+ * @todo This currently considers nobody has prepared rewrite rules blocking access to index.php and api.php
+ */
+ public function get_entry_point () {
+ return substr($this->api_url, 0, -7) . "index.php";
+ }
+
+ /**
+ * Loads the source content into the source_data property.
+ */
+ public function load () {
+ switch ($this->source_mode) {
+ case 'wiki':
+ $url = $this->get_entry_point() . "?title=" . urlencode($this->source_wiki) . "&action=raw";
+ break;
+
+ case 'html':
+ $url = $this->source_html;
+ break;
+
+ default:
+ throw new Exception("$source_mode isn't a valid MediaWikiDataSource source mode.");
+ }
+ $this->source_data = file_get_contents($url, false, get_http_context());
+ }
+
+ /**
+ * Gets categories, from cache or API.
+ *
+ * @param $bypassCache If true, bypass the cache; otherwise, use the cached result if available.
+ * @return Array an single dimension array, each row a category, including Category: prefix.
+ */
+ public function get_categories ($bypassCache = false) {
+ if ($this->source_mode != 'wiki') {
+ throw new Exception("get_categories is only supported in wiki mode.");
+ }
+
+ //Loads cache information
+ $cache = Cache::load();
+ $key = 'tools-ds-mwcats-' . md5($this->api_url . $this->source_wiki);
+ if (!$bypassCache && $data = $cache->get($key)) {
+ return unserialize($data);
+ }
+
+ //API query
+ $api = new MediaWikiBot($this->api_url);
+ $reply = $api->query([
+ 'prop' => 'categories',
+ 'titles' => $this->source_wiki,
+ 'cllimit' => 500,
+ ]);
+
+ //Processes the query reply and caches it
+ $reply = array_shift($reply['query']['pages']);
+ $categories = [];
+ foreach ($reply['categories'] as $category) {
+ $categories[] = $category['title'];
+ }
+ $cache->set($key, serialize($categories));
+
+ return $categories;
+ }
+}
+
+/**
+ * A MediaWiki data source, matching a Wikipedia project.
+ *
+ * @todo use case to get a wikipedia specific class: do we need WP specific helper methods?
+ */
+class WikipediaDataSource extends MediaWikiDataSource {
+ /**
+ * Initializes a new instance of the WikipediaDataSource class
+ *
+ * @param $source The source target, article title in wiki mode, article URL in html mode
+ * @param $mode The source mode
+ * @param $language The language project (e.g. "en")
+ */
+ public function __construct ($source, $mode, $language) {
+ parent::__construct($source, $mode);
+ $this->api_url = "http://$language.wikipedia.org/w/api.php";
+ }
+}
+
+/**
+ * French Wikipedia data source.
+ *
+ * @todo use case to get a fr.wikipedia specific class: do we need fr. specific helper methods?
+ */
+class FrWikipediaDataSource extends WikipediaDataSource {
+ /**
+ * Initializes a new instance of the FrWikipediaDataSource class
+ *
+ * @param $source The source target, article title in wiki mode, article URL in html mode
+ * @param $mode The source mode
+ */
+ public function __construct ($source = false, $mode = 'wiki') {
+ parent::__construct($source, $mode, 'fr');
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/infographics/datasources/pol.fr.senat.php b/infographics/datasources/pol.fr.senat.php
new file mode 100644
index 0000000..99acfd6
--- /dev/null
+++ b/infographics/datasources/pol.fr.senat.php
@@ -0,0 +1,62 @@
+<?php
+
+require_once('mediawikidatasources.php');
+
+/**
+ * Sénateurs de France
+ */
+class SenateursFrance extends FrWikipediaDataSource {
+ /**
+ * Loads data
+ */
+ public function load () {
+ $this->source_mode = 'html';
+ $this->source_html = "http://fr.wikipedia.org/wiki/Liste_des_sénateurs_français_(période_2011-2014)";
+ parent::load();
+ }
+
+ /**
+ * Gets the list of senators
+ *
+ * @return Array The list of senators, each item an array with URL, name and born properties.
+ */
+ public function get_senateurs () {
+ $data = string_between($this->source_data, '<table class="wikitable alternance sortable">', '</table>', true, true);
+ $data = get_array_from_html_table($data, false);
+ array_shift($data);
+
+ $senateurs = [];
+ foreach ($data as $item) {
+ $matches = [];
+ if (preg_match('/href="(.*)" title="(.*)"/', $item[0], $matches)) {
+ $senateur = [];
+
+ //URL
+ $senateur['URL'] = "http://fr.wikipedia.org" . $matches[1];
+
+ //Name
+ $title = substr($senateur['URL'], 29);
+ $name = str_replace('_', ' ', urldecode($title));
+ $pos = strpos($name, '(');
+ if ($pos !== false) {
+ $name = substr($name, 0, $pos - 1);
+ }
+ $senateur['name'] = $name;
+
+ //Birth year
+ $ds = new FrWikipediaDataSource($title);
+ $categories = $ds->get_categories();
+ foreach ($categories as $category) {
+ $matches = [];
+ if (preg_match('/Catégorie:Naissance en ([0-9]{4})/', $category, $matches)) {
+ $senateur['born'] = $matches[1];
+ }
+ }
+
+ $senateurs[] = $senateur;
+ }
+ }
+
+ return $senateurs;
+ }
+}
diff --git a/infographics/parlement-fr.php b/infographics/parlement-fr.php
new file mode 100644
index 0000000..1f559a7
--- /dev/null
+++ b/infographics/parlement-fr.php
@@ -0,0 +1,101 @@
+<div class="four columns">
+<?php
+require_once('datasources/pol.fr.senat.php');
+
+//Gets list of Sénateurs.
+$ds = new SenateursFrance();
+$ds->load();
+$senateurs = $ds->get_senateurs();
+
+/**
+ * Gets a count of items, grouped a key.
+ *
+ * This achieves the same result than SQL queries like:
+ * SELECT foo, COUNT(foo) AS c FROM quux GROUP BY foo ORDER BY c DESC;
+ *
+ * @param $objects an array, each line being an array
+ * @param $by the grouping key
+ * @return $array an array, each line having the key value as key, and the count as value
+ */
+function count_by ($array, $by) {
+ $count = [];
+
+ foreach ($array as $row) {
+ $key = $row[$by];
+ if (isset($count[$key])) {
+ $count[$key]++;
+ } else {
+ $count[$key] = 1;
+ }
+ }
+ arsort($count, SORT_NUMERIC);
+
+ return $count;
+}
+
+// HTML output
+echo '<h2>Sénateurs</h2><table class="twelve"><thead><tr><th>Nom</th><th>Né en</th></tr></thead><tbody>';
+foreach ($senateurs as $senateur) {
+ echo "<tr><td><a href='$senateur[URL]'>$senateur[name]</a></td><td>$senateur[born]</td></tr>";
+}
+echo "</tbody></table></div>";
+?>
+<div class="eight columns">
+<h2>Distribution par année de naissance</h2>
+<div id="chart"></div>
+<div id="chart-1980"></div>
+<p>Les données pour l'Assemblée Nationale ne sont pas encore disponibles.</p>
+</div>
+<script>
+var chartParams = {
+ title: {
+ text: "Distribution des parlementaires français par année de naissance."
+ },
+ legend: {
+ visible: true
+ },
+ seriesDefaults: {
+ type: "scatter"
+ },
+ series: [{
+ name: "Sénat",
+ data: [
+<?php
+$count = count_by($senateurs, 'born');
+$data = [];
+foreach ($count as $key => $value) {
+ $data[] = "[$key, $value]";
+}
+echo implode(', ', $data);
+?>
+ ]
+ }],
+ xAxis: {
+ min: 1920,
+ max: 1990,
+ labels: {
+ format: "{0}"
+ },
+ title: {
+ text: "Année de naissance"
+ }
+ },
+ yAxis: {
+ max: 30,
+ labels: {
+ format: "{0}"
+ },
+ title: {
+ text: "Nombre d'élus"
+ }
+ },
+ tooltip: {
+ visible: true,
+ format: "{1} sénateurs nés en {0}"
+ }
+};
+$("#chart").kendoChart(chartParams);
+chartParams.xAxis.max = 1976;
+$("#chart-1980").kendoChart(chartParams);
+
+</script>

File Metadata

Mime Type
text/x-diff
Expires
Sat, Mar 21, 06:51 (19 h, 41 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3545644
Default Alt Text
(23 KB)

Event Timeline