New model (only php) => (1) Load config from univ-pau.fr (2) Fetch png calendars (3) retrieve events (only by colors) + its hours:minutes

This commit is contained in:
xdrm-brackets 2017-09-12 17:22:18 +02:00
parent 571b1f995c
commit 48d6bd422e
9 changed files with 553 additions and 235 deletions

View File

@ -0,0 +1,269 @@
<?php
namespace service;
class CalendarExtractor{
/* [1] Attributes
=========================================================*/
private $start_d = null; // 1st day date
private $img_url = null; // image url
private $img_res = null; // image resource
private $event = []; // events
private $event_t = [ 0 ]; // types of events
/* [2] Constants
=========================================================*/
public static $start_y = 79; // start y
public static $stop_y = 699; // stop y
public static $start_h = 8; // start hour
public static $stop_h = 20; // stop hour
/* (1) Builds a calendar extractor
*
* @img_url<String> URL of the string to extract from
* @start_d<String> Date of the first day
*
* @return instance<CalendarExtractor> Instance
*
---------------------------------------------------------*/
public function __construct($img_url=null, $start_d=null){
/* [1] Check arguments
=========================================================*/ {
/* (1) Check type */
if( !is_string($img_url) || !is_string($start_d) )
throw new \Exception("CalendarExtractor.__construct(<String>, <String>) expected but CalendarExtractor.__construct(<".gettype($img_url).">, <".gettype($start_d).">) received");
/* (2) Check @img_url link availability */
if( !($img_head=@get_headers($img_url)) )
throw new \Exception("CalendarExtractor.__construct(<URL>, <String>) received but cannot reach <URL>");
if( !preg_match('@HTTP.+200@', $img_head[0]) )
throw new \Exception("CalendarExtractor.__construct(<URL>, <String>) received but cannot reach <URL>");
/* (3) Check @start_d format */
if( !preg_match("@^\d{1,2}-\d{1,2}-\d{3,}$@", $start_d) )
throw new \Exception("CalendarExtractor.__construct(<String>, <DATE>) received <DATE> has not the correct format");
}
/* [2] Fetch file
=========================================================*/ {
/* (1) Try to open file with GD */
$this->img_res = @imagecreatefrompng($img_url);
/* (2) Manage error */
if( !$this->img_res )
throw new \Exception("URL is not a JPEG image, or is unreachable");
/* (3) Register data */
$this->img_url = $img_url;
$this->start_d = $start_d;
}
}
/* (2) Extracts calendar data from image
*
* @return error<bool> FALSE on error
*
---------------------------------------------------------*/
public function process(){
/* [1] Global variables
=========================================================*/ {
/* (1) Image size */ {
// {1} Request for size //
$img_siz = @getimagesize($this->img_url);
// {2} If error //
if( !$img_siz )
throw new \Exception("Cannot get image size");
$img_siz = [
'w' => $img_siz[0],
'h' => $img_siz[1]
];
}
}
/* [2] Extract day limits
=========================================================*/ {
/* (1) Will contain the column+1 w index */
$col_ind = [];
/* (2) Extract column indexes */
for( $x = 0 ; $x < $img_siz['w'] ; $x++ ){
if( $this->getColor($x, 62) <= 10 )
$col_ind[] = $x+1;
}
}
/* [3] For each day -> get events
=========================================================*/ {
/* (1) For each day */
foreach($col_ind as $day_n=>$col_x){
// {1.1} Create the day in events //
$this->event[$day_n] = [];
// {1.2} if inside a course current color, else 0 //
$cur_col = 0x0;
/* (2) For each y pixel -> exctract event */
for( $y = self::$start_y ; $y < self::$stop_y ; $y++ ){
/* (3) Get current color + next */
$p = $this->getColor($col_x, $y);
$p1 = $this->getColor($col_x, $y+1);
/* (4) If on black pixel and next not white */
if( $p == 0 && $p1 != 0xffffff ){
// {1} calculate time //
$time = $this->yToTime($day_n, $y);
// {2} Store new event type (if missing) //
if( !isset($this->event_t[$p1]) )
$this->event_t[$p1] = $this->event_t[0]++;
// {3} Store event start //
$this->event[$this->event_t[$p1]][$time] = [];
// {4} Seek end of event //
$y++;
while( $y < self::$stop_y && $this->getColor($col_x, $y) != 0 )
$y++;
// {5} If end reached //
$this->event[$this->event_t[$p1]][$time] = $this->yToTime($day_n, $y);
}
}
}
}
var_dump($this->event);
die(1);
}
/* (3) Get a pixel's color
*
* @x<int> X coordinate
* @y<int> Y coordinate
*
* @return color<u_int32> Raw color
*
---------------------------------------------------------*/
private function getColor($x, $y){
return imagecolorat($this->img_res, $x, $y);
}
/* (4) Get time from a y-coordinate
*
* @day_n<int> Day relative index
* @y<int> y Coordinate
*
* @return time<String> Formatted time (HH:mm)
*
---------------------------------------------------------*/
private function yToTime($day_n, $y){
/* [1] Get the date
=========================================================*/ {
/* (1) Get the day's date */
$day_ts = strtotime($this->start_d." + $day_n days");
/* (2) Format it */
$day = date('d-m-Y', $day_ts);
}
/* [2] Get the time
=========================================================*/{
/* (1) Get the time */
$time = self::$start_h + (self::$stop_h-self::$start_h) * ($y-self::$start_y) / (self::$stop_y-self::$start_y);
/* (2) Calculate hour form time */
$hour = floor($time);
/* (3) Calculate min from time */
$min = round( 60 * ($time-$hour) );
/* (4) Round minutes to 10min */
$min = floor($min/10)*10;
/* (5) Format to 2-digit */
$hour = ( $hour < 10 ) ? "0$hour" : $hour;
$min = ( $min < 10 ) ? "0$min" : $min ;
}
return "$day $hour:$min:00";
}
/* (5) Generate ICS output
*
* @return ics<String> ICS Representation of the events
*
---------------------------------------------------------*/
// public function toIcs();
}

208
build/service/Config.php Normal file
View File

@ -0,0 +1,208 @@
<?php
namespace service;
class Config{
/* [1] Attributes
=========================================================*/
private $diplomes = null;
private $periods = null;
private static function monthAsso(){
return [
'janvier' => '01',
'février' => '02',
'mars' => '03',
'avril' => '04',
'mai' => '05',
'juin' => '06',
'juillet' => '07',
'août' => '08',
'septembre' => '09',
'octobre' => '10',
'novembre' => '11',
'décembre' => '12'
];
}
/* (1) Constructs a filled config object
*
* @d_list<Array> List of the diplomes ( ID => name )
* @p_list<Array> List of the periods ( ID => first day's date )
*
* @return this<Config> New instance
*
---------------------------------------------------------*/
private function __construct($d_list=null, $p_list=null){
/* [1] Check arguments (type: array)
=========================================================*/
if( !is_array($d_list) || !is_array($p_list) )
throw new \Exception("Config.__construct(<Array>, <Array) expected but Config.__construct(<".gettype($d_list).">, <".gettype($d_list).">) received");
/* [2] Basic setter
=========================================================*/
/* (1) Set the diplomes' list */
$this->diplomes = $d_list;
/* (2) Set the periods' list */
$this->periods = $p_list;
}
/* (2) Loads the configuration from URL
*
* @d_script<String> URL of the script containing the diplomes list
* @p_script<String> URL of the script containing the periods list
*
* @return instance<Config> The created instance
* NULL on error
*
---------------------------------------------------------*/
public static function load($d_script=null, $p_script=null){
/* [1] Check arguments (type + validity)
=========================================================*/ {
/* (1) Check arguments' types (string, string) */
if( !is_string($d_script) || !is_string($p_script) )
throw new \Exception("Config::load(<Array>, <Array) expected but Config::load(<".gettype($d_script).">, <".gettype($d_script).">) received");
/* (2) Check @d_script URL validity */
if( !($d_h=@get_headers($d_script)) )
throw new \Exception("Config::load(<1>, <2>) received but cannot reach <1>");
/* (3) Check @p_script URL validity */
if( !($p_h=@get_headers($p_script)) )
throw new \Exception("Config::load(<1>, <2>) received but cannot reach <1>");
/* (4) Check image exists @dscript */
if( !preg_match('@HTTP.+200@', $d_h[0]) )
throw new \Exception("Config::load(<1>, <2>) received but cannot reach <1>");
/* (5) Check image exists @dscript */
if( !preg_match('@HTTP.+200@', $p_h[0]) )
throw new \Exception("Config::load(<1>, <2>) received but cannot reach <1>");
}
/* [2] Get file cursors
=========================================================*/ {
/* (1) Try to get file cursors */
try{
$d_cur = new \SplFileObject($d_script, "r");
$p_cur = new \SplFileObject($p_script, "r");
/* (2) Raise on failure */
}catch(\Exception $e){
throw new \Exception("Config::load(<1>, <2>) cannot get a cursor on a one of both files");
}
}
/* [3] Filter and register content
=========================================================*/{
/* (1) Manage diplomes
---------------------------------------------------------*/ {
/* (1) Initialize diplomes' list */
$d_list = [];
/* (2) Fetch each line and extract data */
while( !$d_cur->eof() ){
// {1} If does not match -> go to next line //
if( !preg_match('@"grDiplome","(?:&lt;)?(.+)(?:&gt;)?","T(.+)"@i', $d_cur->fgets(), $m) )
continue;
// {2} Register into diplome list //
$d_list[ "T${m[2]}" ] = html_entity_decode($m[1]);
}
/* (2) Close file cursor */
$d_cur = null;
}
/* (2) Manage periods
---------------------------------------------------------*/{
/* (1) Initialize periods' list */
$p_list = [];
/* (2) Fetch each line and extract data */
while( !$p_cur->eof() ){
// {1} If does not match -> go to next line //
if( !preg_match('@"T\d+","du \d+ au (\d+) ([a-z]+) (\d+)","T\d+S(.+)"@i', $p_cur->fgets(), $m) )
continue;
// {2} Get numeric month number //
$month = self::monthAsso()[ $m[2] ];
// {3} Get monday date //
$mon = date( 'd-m-Y', strtotime("${m[1]}-$month-${m[3]} - 5 days") );
// {4} Register into the list //
$p_list[ "S${m[4]}" ] = $mon;
}
/* (2) Close file cursor */
$p_cur = null;
}
}
/* [4] Return the instance
=========================================================*/
return new Config($d_list, $p_list);
}
/* (3) Getter diplomes
*
* @return diplomes<Array> Diplome list
*
---------------------------------------------------------*/
public function getDiplomes(){
return $this->diplomes;
}
/* (4) Getter periods
*
* @return periods<Array> Period list
*
---------------------------------------------------------*/
public function getPeriods(){
return $this->periods;
}
}

65
build/service/Updater.php Normal file
View File

@ -0,0 +1,65 @@
<?php
namespace service;
class Updater{
/* [1] Attributes
=========================================================*/
private $config = null;
/* (1) Constructs and initialise an updater
*
* @return instance<Updater> New Updater
*
---------------------------------------------------------*/
public function __construct(){
/* [1] Fetch config
=========================================================*/ {
/* (1) Try to load the configuration */
$this->config = Config::load("http://sciences.univ-pau.fr/edt/_ressource.js", "http://sciences.univ-pau.fr/edt/_periode.js");
/* (2) If cannot fetch config */
if( !($this->config instanceof Config) )
throw new \Exception("Cannot fetch configuration");
}
}
/* (2) Update the ICS files
*
* @return error<bool> FALSE on error
*
---------------------------------------------------------*/
public function update(){
/* [1] Browse ech diplome
=========================================================*/
foreach($this->config->getDiplomes() as $d_id=>$d_name){
/* (1) Browse each date
---------------------------------------------------------*/
foreach($this->config->getPeriods() as $p_id=>$p_date){
/* (1) Load image in the extractor */
var_dump("http://sciences.univ-pau.fr/edt/diplomes/${d_id}${p_id}.png");
$calext = new CalendarExtractor("http://sciences.univ-pau.fr/edt/diplomes/${d_id}${p_id}.png", $p_date);
/* (2) Extract calendar data */
$calext->process();
}
}
}
}

View File

@ -1,16 +0,0 @@
<?php
$monthList = [
'janvier' => '01',
'février' => '02',
'mars' => '03',
'avril' => '04',
'mai' => '05',
'juin' => '06',
'juillet' => '07',
'août' => '08',
'septembre' => '09',
'octobre' => '10',
'novembre' => '11',
'décembre' => '12'
];

View File

@ -1,79 +0,0 @@
<?php
// Absolute root dir
$ABSROOT = dirname(__DIR__);
require_once "$ABSROOT/lib/months.php";
/* [1] Check arguments
=========================================================*/
/* (1) If not enough -> abort */
if( $argc <= 2 )
exit(1);
/* (2) If @type incorrect */
if( !in_array($argv[1], ['cursus', 'period']) )
die(" * incorrect file type\n");
/* (3) Check given file */
if( !file_exists($argv[2]) )
die(" * file does not exist\n");
/* [2] Try to access file's content
=========================================================*/
/* (1) Read file */
$raw = file_get_contents($argv[2]);
/* (2) Manage error */
if( !is_string($raw) )
die(" * Cannot read file\n");
/* (3) Split by lines */
$raw = explode("\n", $raw);
/* [3] Parse data
=========================================================*/
/* (1) Prepare the output list */
$list = [];
/* (2) Cursur parser */
if( $argv[1] == 'cursus' ){
foreach($raw as $line)
if( preg_match('@"grDiplome","(?:&lt;)?(.+)(?:&gt;)?","T(.+)"@i', $line, $m) )
$list[ html_entity_decode($m[1]) ] = "T${m[2]}";
/* (3) Period parser */
}else{
$first = null;
foreach($raw as $line){
if( preg_match('@"T\d+","du \d+ au (\d+) ([a-z]+) (\d+)","T\d+S(.+)"@i', $line, $m) ){
/* (3.1) Translate month */
$month = $monthList[$m[2]];
/* (3.2) Get date of monday */
$list[ "S${m[4]}" ] = date('d-m-Y', strtotime("${m[1]}-$month-${m[3]} - 5 days"));
}
}
}
/* [4] Write data back
=========================================================*/
if( !file_put_contents("$ABSROOT/../../tmp/${argv[1]}.json", json_encode($list)) )
die(" * Cannot write parsed data back\n");
exit(0);

View File

@ -1,92 +0,0 @@
<?php
// Absolute root dir
$ABSROOT = dirname(__DIR__);
/* [1] Check needed files
=========================================================*/ {
$path = [
'cursus' => "$ABSROOT/../../tmp/cursus.json",
'period' => "$ABSROOT/../../tmp/period.json",
];
/* (1) cursus list */
if( !file_exists($path['cursus']) )
die(" * Missing tmp/cursus.json\n");
/* (2) period list */
if( !file_exists($path['period']) )
die(" * Missing tmp/period.json\n");
}
/* [2] Parse cursus list
=========================================================*/ {
/* (1) Read from file */
$clist = file_get_contents($path['cursus']);
/* (2) Manage error */
if( $clist == false )
die(" * Cannot read cursus file\n");
/* (3) Parse JSON */
$clist = json_decode($clist, true);
/* (4) Manage error */
if( $clist == null )
die(" * Cannot parse cursus file\n");
}
/* [3] Parse period list
=========================================================*/ {
/* (1) Read from file */
$plist = file_get_contents($path['period']);
/* (2) Manage error */
if( $plist == false )
die(" * Cannot read period file\n");
/* (3) Parse JSON */
$plist = json_decode($plist, true);
/* (4) Manage error */
if( $plist == null )
die(" * Cannot parse period file\n");
}
/* [4] Manage each cursus
=========================================================*/ {
/* (1) For each cursus */
foreach($clist as $cname=>$cvalue){
/* (1.2) Create a directory */
if( !file_exists("$ABSROOT/../../tmp/$cvalue") )
file_put_contents("$ABSROOT/../../tmp/$cvalue.ics", "");
/* (1) Download all images
---------------------------------------------------------*/
foreach($plist as $pvalue=>$pdate)
"http://sciences.univ-pau.fr/edt/diplomes/${cvalue}${pvalue}.png"; // image file
}
}

View File

@ -1,48 +0,0 @@
#!/bin/bash
# Absolute root dir
ABSROOT=$( dirname $(realpath $0) );
# [1] Download the list of Diplomes
#========================================================#
# (1) Get the diplomes list #
wget http://sciences.univ-pau.fr/edt/_ressource.js -qO $ABSROOT/../../tmp/cursus.js && echo "* downloaded successfully" || echo "* download failed" || exit 1;
# (2) Get Period list #
wget http://sciences.univ-pau.fr/edt/_periode.js -qO $ABSROOT/../../tmp/period.js && echo "* downloaded successfully" || echo "* download failed" || exit 1;
# [2] Parse these lists
#========================================================#
# (1) Parse the diplomes list #
php $ABSROOT/lib/parse.php cursus $ABSROOT/../../tmp/cursus.js && echo "* parsed successfully" || echo "* parsing failed" || exit 1;
# (2) Parse the period list #
php $ABSROOT/lib/parse.php period $ABSROOT/../../tmp/period.js && echo "* parsed successfully" || echo "* parsing failed" || exit 1;
# [3] Update ICS files
#========================================================#
# (1) Create ICS files #
php $ABSROOT/lib/update.php;
# (2) Remove buffer data #
rm -r $ABSROOT/../../tmp/*.ics
# [X] Remove downloaded original files
#========================================================#
# (1) Remove cursus #
rm $ABSROOT/../../tmp/cursus.js && echo "* removed successfully" || echo "* removing failed" || exit 1;
# (2) Remove period #
rm $ABSROOT/../../tmp/period.js && echo "* removed successfully" || echo "* removing failed" || exit 1;

4
install.sh Normal file
View File

@ -0,0 +1,4 @@
#!/bin/bash
sudo apt-get install php7.0-gd;
sudo service apache2 restart;

View File

@ -1,6 +1,13 @@
<?php require_once '../autoloader.php'; <?php require_once '../autoloader.php';
use \service\Updater;
debug(); debug();
$upd = new Updater();
$upd->update();
// var_dump( imagecreatefrompng("http://sciences.univ-pau.fr/edt/diplomes/T0000000378S0000000000002.png") );
echo "bla"; echo "bla";