From ae15704e7cfd68d4af8e3c9417ce5ddd3a85ff2c Mon Sep 17 00:00:00 2001 From: "vincent@cubedesigners.com" Date: Wed, 9 Jun 2010 09:44:17 +0000 Subject: [PATCH] --- inc/ws/Controlleur/class.ws.ajax.php | 48 ++ inc/ws/Controlleur/class.ws.stats.php | 874 +++++++++++++++++++++++ swf/_src/assets/chapters-back.png | Bin 0 -> 492 bytes swf/_src/assets/chapters-book-over.png | Bin 0 -> 2931 bytes swf/_src/assets/chapters-grip.png | Bin 0 -> 199 bytes swf/_src/assets/chapters-label-field.png | Bin 0 -> 476 bytes swf/_src/assets/chapters-moins.png | Bin 0 -> 954 bytes swf/_src/assets/chapters-move.png | Bin 0 -> 1493 bytes swf/_src/assets/chapters-page-field.png | Bin 0 -> 392 bytes swf/_src/assets/chapters-plus.png | Bin 0 -> 1040 bytes 10 files changed, 922 insertions(+) create mode 100644 inc/ws/Controlleur/class.ws.ajax.php create mode 100644 inc/ws/Controlleur/class.ws.stats.php create mode 100644 swf/_src/assets/chapters-back.png create mode 100644 swf/_src/assets/chapters-book-over.png create mode 100644 swf/_src/assets/chapters-grip.png create mode 100644 swf/_src/assets/chapters-label-field.png create mode 100644 swf/_src/assets/chapters-moins.png create mode 100644 swf/_src/assets/chapters-move.png create mode 100644 swf/_src/assets/chapters-page-field.png create mode 100644 swf/_src/assets/chapters-plus.png diff --git a/inc/ws/Controlleur/class.ws.ajax.php b/inc/ws/Controlleur/class.ws.ajax.php new file mode 100644 index 000000000..7d012cde4 --- /dev/null +++ b/inc/ws/Controlleur/class.ws.ajax.php @@ -0,0 +1,48 @@ +con); + $dao->supprime($args[1]); + $x->addContent('listeBooks', wsUrl::listeBooks()); + } + + public static function searchBooks($args, &$x) + { + $x->addContent('listeBooks', wsUrl::listeBooks()); + } + + public static function pageBooks($args, &$x) + { + self::page('books', $args[1]); + $x->addContent('listeBooks', wsUrl::listeBooks()); + } + + public static function parPageBooks($args, &$x) + { + self::parPage('books', $_POST['par_page']); + $x->addContent('listeBooks', wsUrl::listeBooks()); + } + + public static function sortBooks($args, &$x) + { + self::sort('books', $args[1]); + $x->addContent('listeBooks', wsUrl::listeBooks()); + } + + public static function filtreBooks($args, &$x) + { + if (isset($args[1]) && $args[1] == 'efface') { + self::filtre('books'); + $x->addReload(); + return; + } else { + self::filtre('books', $_POST); + $x->addContent('listeBooks', wsUrl::listeBooks()); + } + } +} + +?> \ No newline at end of file diff --git a/inc/ws/Controlleur/class.ws.stats.php b/inc/ws/Controlleur/class.ws.stats.php new file mode 100644 index 000000000..0d12662d6 --- /dev/null +++ b/inc/ws/Controlleur/class.ws.stats.php @@ -0,0 +1,874 @@ +book = round($d->visitor * 1.2); + }*/ + public static function display($bid, $annee = null, $mois = null) + { + wsDroits::viewBook($bid); + cubePHP::set_memory('512M'); + if (is_null($annee) && is_null($mois)) { + return self::vue_globale($bid); + } + if (is_null($mois)) { + return self::vue_annuelle($bid, $annee); + } + return self::vue_mensuelle($bid, $annee, $mois); + } + + public static function getExtra($extra) + { + $xml = simplexml_load_string('' . $extra . ''); + if ((string)$xml->extraName != '') { + return (string)$xml->extraName; + } + return null; + } + + public static function load_stats($bid, $annee = null, $mois = null) + { + $root = WS_STATS . 'xml/' . $bid; + if (is_null($annee)) { + $xml = $root; + $sort = 'globalSort'; + } else if (is_null($mois)) { + $xml = $root . '/' . $annee; + $sort = 'yearSort'; + } else { + $xml = $root . '/' . $annee . '/' . $mois; + $sort = 'monthSort'; + } + $xml = rtrim($xml, '/'); + $xml .= '.xml'; + if ($x = @simplexml_load_file($xml)) { + if (!is_null($mois)) { + } + $x = call_user_func(array('wsStats', $sort), $x); + self::correctValues($x, $annee, $mois); + return $x; + } + return null; + } + + public static function correctValues($x, $y, $m) + { + foreach(self::$datestocorrect as $date) { + if ($date[2] != $y || $date[1] != $m) { + continue; + } + fb($y, $m); + $days = $x->xpath("//day[@day=" . $date[0] . "]"); + foreach($days as $day) { + break; + } + $visitors = (string)$day['places'] * 1.2; + $visits = $visitors * 1.1; + cubeXML::removeAttribute($day, 'visitors'); + cubeXML::removeAttribute($day, 'visits'); + $day->addAttribute('visitors', $visitors); + $day->addAttribute('visits', $visits); + } + } + + public static function correctPlaces($x) + { + } + + public static function globalSort($xml, $root = 'stats') + { + $res = simplexml_load_string('<' . $root . ' />'); + foreach($xml->attributes() as $k => $v) { + $res->addAttribute($k, $v); + } + $years = array(); + foreach($xml->year as $year) { + $years[(string)$year['year']] = self::yearSort($year, 'year'); + } + ksort($years); + foreach($years as $y) { + cubeXML::append($res, $y); + } + return $res; + } + + public static function yearSort($xml, $root = 'stats') + { + $res = simplexml_load_string('<' . $root . ' />'); + foreach($xml->attributes() as $k => $v) { + $res->addAttribute($k, $v); + } + $months = array(); + foreach($xml->month as $month) { + $months[(string)$month['month']] = $month; + } + + ksort($months); + foreach($months as $month) { + cubeXML::append($res, $month); + } + + return $res; + } + + public static function monthSort($xml, $root = 'stats') + { + $res = simplexml_load_string('<' . $root . ' />'); + foreach($xml->attributes() as $k => $v) { + $res->addAttribute($k, $v); + } + self::daysSort($xml, $res); + self::pagesSort($xml, $res); + self::linksSort($xml, $res); + self::searchesSort($xml, $res); + self::countriesSort($xml, $res); + + return $res; + } + + public static function daysSort($xml, $res) + { + $x = $res->addChild('days'); + $days = array(); + foreach($xml->days->day as $day) { + $days[(string)$day['day']] = $day; + } + ksort($days); + foreach($days as $day) { + $places = (string)$day['places']; + if ($places == 1) { + $visitors = (string)$day['visitors']; + if ($visitors > 10) { + cubeXML::removeAttribute($day, 'places'); + $day->addAttribute('places', round($visitors * 0.99)); + } + } + cubeXML::append($x, $day); + } + } + + public static function pagesSort($xml, $res) + { + $xpages = $res->addChild('pages'); + $pages = array(); + $trans = array(); + foreach($xml->pages->page as $page) { + $pages[(string)$page['page']] = (string)$page['score']; + $trans[(string)$page['page']] = $page; + } + arsort($pages); + foreach($pages as $num => $score) { + cubeXML::append($xpages, $trans[$num]); + } + } + + public static function linksSort($xml, $res) + { + $x = $res->addChild('links'); + $links = array(); + $trans = array(); + foreach($xml->links->link as $link) { + $links[(string)$link['url']] = (string)$link['click']; + $trans[(string)$link['url']] = $link; + } + arsort($links); + $links = array_slice($links, 0, 100, true); + foreach($links as $url => $click) { + cubeXML::append($x, $trans[$url]); + } + } + + public static function searchesSort($xml, $res) + { + $x = $res->addChild('searches'); + $searches = array(); + $trans = array(); + foreach($xml->searches->search as $search) { + $searches[(string)$search['query']] = (string)$search['count']; + $trans[(string)$search['query']] = $search; + } + arsort($searches); + $searches = array_slice($searches, 0, 100, true); + foreach($searches as $q => $count) { + cubeXML::append($x, $trans[$q]); + } + } + + public static function countriesSort($xml, $res) + { + $x = $res->addChild('countries'); + $countries = array(); + $trans = array(); + foreach($xml->countries->country as $country) { + $countries[(string)$country['code']] = (string)$country['visitors']; + $trans[(string)$country['code']] = $country; + } + arsort($countries); + foreach($countries as $code => $visitors) { + cubeXML::append($x, $trans[$code]); + } + } + + public static function getActives($stats, $rr, &$aextra, &$adown, &$adownp, &$aprint, &$afriend) + { + $extra = self::getExtra($rr->extras); + $aextra = ($extra != null && $stats['extras'] > 0); + $adown = ($rr->pdf == 1 && $stats['downloads'] > 0); + $adownp = ($rr->pdf == 1 && $rr->pdfComplex == 1 && $stats['partDownloads'] > 0); + $aprint = ($rr->print == 1); + $afriend = ($rr->friend == 1); + } + + public static function globalDatas($date_creation, $rr, $stats, $afriend, $aprint, $adown, $adownp, $aextra) + { + $res = ''; + $res .= ''; + + $res .= ''; + $res .= ''; + $res .= ''; + + $res .= ''; + if ($afriend) { + $res .= ''; + } + $res .= ''; + if ($aprint) { + $res .= ''; + } + if ($adown) { + $res .= ''; + } + if ($adownp) { + $res .= ''; + } + if ($aextra) { + $res .= ''; + } + $res .= '
' . $date_creation . '' . date(__('d-m-Y'), $rr->date) . '
' . __('Nombre de lieux de visite') . '' . $stats['places'] . '
' . __('Nombre de visiteurs uniques') . '' . $stats['visitors'] . '
' . __('Nombre de visites') . '' . $stats['visits'] . '
' . __('Nombre de pages vues') . '' . $stats['pages'] . '
' . __('Nombre de liens envoyés') . '' . $stats['friends'] . '
' . __('Nombre de liens cliqués') . '' . $stats['links'] . '
' . __("Nombre d'impressions") . '' . $stats['prints'] . '
' . __('Nombre de téléchargements') . '' . $stats['downloads'] . '
' . __('Nombre de téléchargements partiels') . '' . $stats['partDownloads'] . '
' . __('Accès à la rubrique') . ' ' . $extra . '' . $stats['extras'] . '
'; + return $res; + } + + public static function indisponible() + { + $res = wsPage::bh('stats_global'); + $res .= '

' . __('Les statistiques concernant cette période ne sont actuellement pas disponibles') . '

'; + $res .= wsPage::bf(); + return $res; + } + + public static function vue_globale($bid, $annee = null) + { + global $core; + $rr = $core->con->select('SELECT * FROM book WHERE bid=' . $bid); + + $extra = self::getExtra($rr->extras); + + if (is_null($annee)) { + $stats = self::load_stats($bid); + } else { + $stats = self::load_stats($bid, $annee); + } + + if (is_null($stats)) { + return self::indisponible(); + } + + self::getActives($stats, $rr, $aextra, $adown, $adownp, $aprint, $afriend); + + $res = wsPage::bh('stats_global'); + $titre = ($_SESSION['white'])?__('Statistiques de la publication « %s »'):__('Statistiques du fluidbook « %s »'); + $date_creation = ($_SESSION['white'])? __('Date de création de la publication'): __('Date de création du fluidbook'); + $res .= cubeTypographp::typographp(array('texte' => mb_strtoupper(sprintf($titre, $rr->titre))), 'hache2'); + $res .= self::globalDatas($date_creation, $rr, $stats, $afriend, $aprint, $adown, $adownp, $aextra); + $res .= wsPage::bf(); + + $res .= wsPage::bh('stats_detail_mois'); + $res .= cubeTypographp::typographp(array('texte' => mb_strtoupper(sprintf(__('Détail par mois'), $rr->titre))), 'hache2'); + $res .= '
' ; + if (is_null($annee)) { + $res .= self::graph_global($bid, $stats); + } else { + $res .= self::graph_annuel($bid, $annee, $stats); + } + $res .= '
'; + $res .= ''; + $res .= ''; + $res .= ''; + $res .= ''; + $res .= ''; + $res .= ''; + if ($afriend) { + $res .= ''; + } + $res .= ''; + if ($aprint) { + $res .= ''; + } + if ($adown) { + $res .= ''; + } + if ($adownp) { + $res .= ''; + } + if ($aextra) { + $res .= ''; + } + + $res .= ''; + + if (is_null($annee)) { + $years = $stats->year; + } else { + $years = array($stats); + } + + foreach($years as $year) { + if (is_null($annee)) { + $res .= ''; + $res .= ''; + $res .= ''; + $res .= ''; + $res .= ''; + if ($afriend) { + $res .= ''; + } + $res .= ''; + if ($aprint) { + $res .= ''; + } + if ($adown) { + $res .= ''; + } + if ($adownp) { + $res .= ''; + } + if ($aextra) { + $res .= ''; + } + $res .= ''; + } + foreach($year->month as $month) { + $res .= ''; + + $res .= ''; + $res .= ''; + $res .= ''; + $res .= ''; + if ($afriend) { + $res .= ''; + } + $res .= ''; + if ($aprint) { + $res .= ''; + } + if ($adown) { + $res .= ''; + } + if ($adownp) { + $res .= ''; + } + if ($aextra) { + $res .= ''; + } + $res .= ''; + } + } + $res .= '
' . __('Période') . '' . __('Lieux de visite') . '' . __('Visiteurs uniques') . '' . __('Visites') . '' . __('Pages vues') . '' . __('Liens envoyés') . '' . __('Liens cliqués') . '' . __('Impressions') . '' . __('Téléchargements') . '' . __('Téléchargements partiels') . '' . $extra . '
' . $year['year'] . '' . $year['places'] . '' . $year['visitors'] . '' . $year['visits'] . '' . $year['pages'] . '' . $year['friends'] . '' . $year['links'] . '' . $year['prints'] . '' . $year['downloads'] . '' . $year['partDownloads'] . '' . $year['extras'] . '
' . strftime('%B %Y', mktime(0, 0, 0, (string)$month['month'], 15, (string)$month['year'])) . '' . $month['places'] . '' . $month['visitors'] . '' . $month['visits'] . '' . $month['pages'] . '' . $month['friends'] . '' . $month['links'] . '' . $month['prints'] . '' . $month['downloads'] . '' . $month['partDownloads'] . '' . $month['extras'] . '
'; + $res .= wsPage::bf(); + return $res; + } + + public static function graph_global($bid, $stats) + { + wsDroits::viewBook($bid); + global $core; + $img = ROOT . '/images/stats/global-' . $bid . '.png'; + $imgw = WEBROOT . '/images/stats/global-' . $bid . '.png'; + + $s = array(); + foreach ($stats->year as $year) { + foreach($year->month as $month) { + $time = mktime(0, 0, 0, intval((string)$month['month']), 15, (string)$month['year']); + $s[$time]['book'] = $month['visits']; + $s[$time]['page'] = $month['pages']; + $s[$time]['time'] = $time; + $s[$time]['visit'] = $month['visitors']; + } + } + fb($s); + krsort($s); + $s = array_slice($s, 0, 12, true); + // $s = array_reverse($s); + fb($s); + $maxv = 0; + $maxp = 0; + $maxb = 0; + foreach($s as $time => $d) { + $maxb = max($maxb, (string) $d['book']); + $maxp = max($maxp, (string)$d['page']); + $maxv = max($maxv, (string) $d['visit']); + } + + $max = max($maxb, $maxv); + self::getQ($bid, $max, $maxp, $maxpages, $s); + $max = max($maxv, $maxb, $maxp, 1); + if (file_exists($img)) { + unlink($img); + } + if (!file_exists($img) || filemtime($img) < cubeDate::round(null, 'H')) { + $im = imagecreatetruecolor(944, 306); + imagelayereffect($im, IMG_EFFECT_REPLACE); + $trans = imagecolorallocatealpha($im, 244, 244, 241, 0); + imagefill($im, 0, 0, $trans); + imagelayereffect($im, IMG_EFFECT_ALPHABLEND); + $i = 1; + $x0 = 900; + $y0 = 305; + $h = 300; + $c0 = imagecolorallocate($im, 0, 0 , 0); + $c1 = imagecolorallocatealpha($im, 81, 78, 73, 64); + $hp = $h * ($maxp / $max)-2; + $mhp = $y0 - $hp-6; + imagesetstyle($im, array($c1, $c1, $c1, $c1, $c1, $trans, $trans, $trans, $trans)); + imageline($im, 0, $y0 - $hp, 944, $y0 - $hp, IMG_COLOR_STYLED); + $c1 = imagecolorallocate($im, 81, 78, 73); + $c2 = imagecolorallocatealpha($im, 245, 77, 0, 64); + $hb = $h * ($maxb / $max)-1; + $mhb = $y0 - $hb-6; + imagesetstyle($im, array($c2, $c2, $c2, $c2, $c2, $trans, $trans, $trans, $trans)); + imageline($im, 0, $y0 - $hb, 944, $y0 - $hb, IMG_COLOR_STYLED); + $c2 = imagecolorallocate($im, 245, 77, 0); + $c3 = imagecolorallocatealpha($im, 194, 211, 19, 32); + $hv = $h * ($maxv / $max); + $mhv = $y0 - $hv-6; + imagesetstyle($im, array($c3, $c3, $c3, $c3, $c3, $trans, $trans, $trans, $trans)); + imageline($im, 0, $y0 - $hv, 944, $y0 - $hv, IMG_COLOR_STYLED); + $c3 = imagecolorallocate($im, 194, 211, 19); + foreach($s as $t) { + $x0 -= 15; + $hp = $h * ($t['page'] / $max)-2; + $hb = $h * ($t['book'] / $max)-1; + $hv = $h * ($t['visit'] / $max); + imagefilledrectangle($im, $x0-40, $y0 - $hp, $x0, $y0, $c1); + imagerectangle($im, $x0-40, $y0 - $hp, $x0, $y0, $c0); + $x0 -= 5; + imagefilledrectangle($im, $x0-40, $y0 - $hb, $x0, $y0, $c2); + imagerectangle($im, $x0-40, $y0 - $hb, $x0, $y0, $c0); + $x0 -= 5; + imagefilledrectangle($im, $x0-40, $y0 - $hv, $x0, $y0, $c3); + imagerectangle($im, $x0-40, $y0 - $hv, $x0, $y0, $c0); + $i++; + $x0 -= 50; + } + + imageline($im, 0 , $y0, 944 , $y0 , $c0); + imagepng($im, $img); + } + $res = '
' . $maxpages . '
'; + $res .= '
' . $maxb . '
'; + $res .= '
' . $maxv . '
'; + $res .= '' . __('Statistiques globales') . ''; + $s = array_reverse(array_pad($s, 12, false), true); + $res .= ''; + foreach($s as $time => $val) { + if (!$val) { + $res .= ''; + } else { + $res .= ''; + } + } + $res .= ''; + $res .= '
' . cubeMedia::spacer(75, 20) . '' . strftime('%b %y', $val['time']) . '' . cubeMedia::spacer(44, 20) . '
'; + $res .= ''; + $res .= ''; + $res .= ''; + $res .= ''; + $res .= '
' . __('Pages vues') . '' . __('Visites') . '' . __('Visiteurs uniques') . '
'; + return $res; + } + + /** + * wsStats::vue_annuelle() + * + * @param mixed $bid + * @param mixed $annee + * @return + */ + public static function vue_annuelle($bid, $annee) + { + return self::vue_globale($bid, $annee); + } + + public static function getQ($bid, $max, &$maxp, &$maxpages, &$s) + { + global $core; + $rrr = $core->con->select('SELECT pages FROM book WHERE bid=' . $bid); + $maxpages = $maxp; + $q = max($rrr->pages / 5, 1); + $maxp /= $q; + $maxp = max($max * 4, $maxp); + $q = $maxpages / $maxp; + foreach($s as $time => $t) { + $s[$time]['page'] = intval($s[$time]['page'] / $q); + } + } + + public static function graph_annuel($bid, $a, $stats) + { + wsDroits::viewBook($bid); + global $core; + $img = ROOT . '/images/stats/annuel-' . $a . '-' . $bid . '.png'; + $imgw = WEBROOT . '/images/stats/annuel-' . $a . '-' . $bid . '.png'; + $maxv = 0; + $maxp = 0; + $maxb = 0; + $s = array(); + foreach ($stats->month as $month) { + $maxb = max($maxb, (string)$month['visits']); + $maxp = max($maxp, (string) $month['pages']); + $maxv = max($maxv, (string)$month['visitors']); + $time = cubeDate::round(mktime(0, 0, 0, (string)$month['month'], 15, (string)$month['year']), 'm'); + $s[$time] = array(); + $s[$time]['book'] = (string)$month['visits']; + $s[$time]['page'] = (string)$month['pages']; + $s[$time]['visit'] = (string) $month['visitors']; + } + // . + $max = max($maxb, $maxv); + self::getQ($bid, $max, $maxp, $maxpages, $s); + krsort($s); + $max = max($maxb, $maxv, $maxp); + $months = cubeDate::getMonths($a); + @unlink($img); + if (!file_exists($img) || filemtime($img) < cubeDate::round(null, 'H')) { + $im = imagecreatetruecolor(944, 306); + imagelayereffect($im, IMG_EFFECT_REPLACE); + $trans = imagecolorallocatealpha($im, 244, 244, 241, 0); + imagefill($im, 0, 0, $trans); + imagelayereffect($im, IMG_EFFECT_ALPHABLEND); + $i = 1; + $x0 = 0; + $y0 = 305; + $h = 300; + $c0 = imagecolorallocate($im, 0, 0 , 0); + $c1 = imagecolorallocatealpha($im, 81, 78, 73, 64); + $hp = $h * ($maxp / $max)-2; + $mhp = $y0 - $hp-6; + imagesetstyle($im, array($c1, $c1, $c1, $c1, $c1, $trans, $trans, $trans, $trans)); + imageline($im, 0, $y0 - $hp, 944, $y0 - $hp, IMG_COLOR_STYLED); + $c1 = imagecolorallocate($im, 81, 78, 73); + $c2 = imagecolorallocatealpha($im, 245, 77, 0, 64); + $hb = $h * ($maxb / $max)-1; + $mhb = $y0 - $hb-6; + imagesetstyle($im, array($c2, $c2, $c2, $c2, $c2, $trans, $trans, $trans, $trans)); + imageline($im, 0, $y0 - $hb, 944, $y0 - $hb, IMG_COLOR_STYLED); + $c2 = imagecolorallocate($im, 245, 77, 0); + $c3 = imagecolorallocatealpha($im, 194, 211, 19, 32); + $hv = $h * ($maxv / $max); + $mhv = $y0 - $hv-6; + imagesetstyle($im, array($c3, $c3, $c3, $c3, $c3, $trans, $trans, $trans, $trans)); + imageline($im, 0, $y0 - $hv, 944, $y0 - $hv, IMG_COLOR_STYLED); + $c3 = imagecolorallocate($im, 194, 211, 19); + foreach($months as $m => $t) { + if (isset($s[$t])) { + $x0 += 15; + $hp = $h * ($s[$t]['page'] / $max)-2; + $hb = $h * ($s[$t]['book'] / $max)-1; + $hv = $h * ($s[$t]['visit'] / $max); + imagefilledrectangle($im, $x0 + 40, $y0 - $hp, $x0, $y0, $c1); + imagerectangle($im, $x0 + 40, $y0 - $hp, $x0, $y0, $c0); + $x0 += 5; + imagefilledrectangle($im, $x0 + 40, $y0 - $hb, $x0, $y0, $c2); + imagerectangle($im, $x0 + 40, $y0 - $hb, $x0, $y0, $c0); + $x0 += 5; + imagefilledrectangle($im, $x0 + 40, $y0 - $hv, $x0, $y0, $c3); + imagerectangle($im, $x0 + 40, $y0 - $hv, $x0, $y0, $c0); + $i++; + $x0 += 50; + } else { + $x0 += 75; + } + } + + imageline($im, 0 , $y0, 944 , $y0 , $c0); + imagepng($im, $img); + } + $res = '
' . $maxpages . '
'; + $res .= '
' . $maxb . '
'; + $res .= '
' . $maxv . '
'; + $res .= '' . __('Statistiques annuelles') . ''; + $res .= ''; + foreach($months as $m => $t) { + $res .= ''; + } + $res .= ''; + $res .= '
' . strftime('%b %y', $t) . '' . cubeMedia::spacer(44, 20) . '
'; + $res .= ''; + $res .= ''; + $res .= ''; + $res .= ''; + $res .= '
' . __('Pages vues') . '' . __('Visites') . '' . __('Visiteurs uniques') . '
'; + return $res; + } + + public static function vue_mensuelle($bid, $annee, $mois) + { + wsDroits::viewBook($bid); + $datestocorrect = array(mktime(0, 0, 0, 11, 23, 2009), mktime(0, 0, 0, 12, 8, 2009), mktime(0, 0, 0, 12, 9, 2009)); + global $core; + $rr = $core->con->select('SELECT *,book.date AS date FROM book,user WHERE user.uid=book.uid AND bid=' . $bid); + $extra = self::getExtra($rr->extras); + $stats = self::load_stats($bid, $annee, $mois); + + if (is_null($stats)) { + return self::indisponible(); + } + + self::getActives($stats, $rr, $aextra, $adown, $adownp, $aprint, $afriend); + + $time_page = mktime(0, 0, 0, $mois, 15, $annee); + $res = wsPage::bh('stats_global'); + $titre = ($_SESSION['white'])?__('Statistiques de la publication « %s »'):__('Statistiques du fluidbook « %s »'); + $date_creation = ($_SESSION['white'])? __('Date de création de la publication'): __('Date de création du fluidbook'); + $res .= cubeTypographp::typographp(array('texte' => mb_strtoupper(sprintf($titre, $rr->titre) . ' - ' . strftime('%B %Y', $time_page))), 'hache2'); + $res .= self::globalDatas($date_creation, $rr, $stats, $afriend, $aprint, $adown, $adownp, $aextra); + $res .= wsPage::bf(); + $res .= wsPage::bh('stats_detail_mois'); + $res .= cubeTypographp::typographp(array('texte' => mb_strtoupper(__('Détail par jour') . ' - ' . strftime('%B %Y', $time_page))), 'hache2'); + $res .= '
' . self::graph_mensuel($bid, $annee, $mois, $stats) . '
'; + $res .= ''; + $res .= ''; + + $res .= ''; + + $res .= ''; + $res .= ''; + $res .= ''; + $res .= ''; + $res .= ''; + + foreach ($stats->days->day as $day) { + $res .= ''; + + $res .= ''; + $res .= ''; + $res .= ''; + $res .= ''; + $res .= ''; + $res .= ''; + } + $res .= '
' . __('Jour') . '' . __('Lieux de visite') . '' . __('Visiteurs uniques') . '' . __('Visites') . '' . __('Pages vues') . '' . __('Liens cliqués') . '
' . strftime('%A %d', mktime(0, 0, 0, $mois, (string)$day['day'], $annee)) . '' . $day['places'] . '' . $day['visitors'] . '' . $day['visits'] . '' . $day['views'] . '' . $day['links'] . '
'; + + $res .= wsPage::bf(); + $res .= wsPage::bh('stats_detail_pages'); + $res .= cubeTypographp::typographp(array('texte' => mb_strtoupper(__('Pages les plus vues') . ' - ' . strftime('%B %Y', $time_page))), 'hache2'); + $res .= ''; + $res .= ''; + if ($rr->stats_score == 1) { + $res .= ''; + } + $res .= ''; + $res .= ''; + if ($rr->bookmark == 1) { + $res .= ''; + } + if ($rr->print == 1) { + $res .= ''; + } + + foreach ($stats->pages->page as $page) { + $p = (string)$page['page']; + if ($p > $rr->pages || cubeMath::isOdd($p)) { + continue; + } + if ($p == 0) { + $pagen = '1'; + } elseif ($p == $rr->pages) { + $pagen = $p; + } else { + $pagen = $p; + $pagen .= '-'; + $pagen .= ($p + 1); + } + $res .= ''; + if ($rr->stats_score == 1) { + $res .= ''; + } + $res .= ''; + $res .= ''; + if ($rr->bookmark == 1) { + $res .= ''; + } + if ($rr->print == 1) { + $res .= ''; + } + } + $res .= '
' . __('Pages') . '' . __('Score') . '' . __('Vues') . '' . __('Zooms') . '' . __('Marques-pages') . '' . __('Impressions') . '
' . $pagen . '' . $page['score'] . '' . $page['views'] . '' . $page['zooms'] . '' . $page['bookmarks'] . '' . $page['prints'] . '
'; + + $res .= wsPage::bf(); + if ($rr->search == 0) { + $idl = 'stats_links_2'; + $idc = 'stats_country_2'; + } else { + $idl = 'stats_links'; + $idc = 'stats_country'; + } + + $res .= '
'; + $res .= wsPage::bh($idl); + $res .= cubeTypographp::typographp(array('texte' => mb_strtoupper(__('Liens les plus cliqués'))), 'hache2'); + $res .= ''; + $res .= ''; + foreach ($stats->links->link as $link) { + $uurl = (string)$link['url']; + $nb = (string)$link['click']; + if (stristr($uurl, 'mailto:') || stristr($uurl, 'http://')) { + $url = substr($uurl, 7); + } else { + $url = $uurl; + } + if (strlen($url) > 30) { + $url = substr($url, 0, 30) . '...'; + } + $res .= ''; + } + $res .= '
' . __('URL') . '' . __('Clics') . '
' . $url . '' . $nb . '
'; + + $res .= wsPage::bf(); + if ($rr->search == 1) { + $res .= wsPage::bh('stats_search'); + $res .= cubeTypographp::typographp(array('texte' => mb_strtoupper(__('Mots les plus recherchés'))), 'hache2'); + $res .= ''; + $res .= ''; + foreach ($stats->searches->search as $search) { + $res .= ''; + } + $res .= '
' . __('Mot') . '' . __('Recherches') . '
' . $search['query'] . '' . $search['count'] . '
'; + $res .= wsPage::bf(); + } + + $res .= wsPage::bh($idc); + $res .= cubeTypographp::typographp(array('texte' => mb_strtoupper(__('Origine des visiteurs'))), 'hache2'); + $res .= ''; + $res .= ''; + + foreach ($stats->countries->country as $country) { + $pays = $country['code']; + if (!$c = cubeCountry::getCountry($pays)) { + $c = __('Origine inconnue'); + } + $res .= ''; + } + $res .= '
' . __('Pays') . '' . __('Visiteurs') . '
' . cubeCountry::getFlag($pays) . ' ' . ucfirst(mb_strtolower($c)) . '' . $country['visitors'] . '
'; + $res .= wsPage::bf(); + $res .= '
'; + return $res; + } + + public static function graph_mensuel($bid, $a, $m, $stats) + { + wsDroits::viewBook($bid); + global $core; + $img = ROOT . '/images/stats/mensuel-' . $a . '-' . $m . '-' . $bid . '.png'; + $imgw = WEBROOT . '/images/stats/mensuel-' . $a . '-' . $m . '-' . $bid . '.png'; + $lm = cubeDate::limitMonth($a, $m); + $datestocorrect = array(mktime(0, 0, 0, 11, 23, 2009), mktime(0, 0, 0, 12, 8, 2009), mktime(0, 0, 0, 12, 9, 2009)); + $maxv = 0; + $maxp = 0; + $maxb = 0; + $v = array(); + $s = array(); + foreach ($stats->days->day as $day) { + $time = mktime(0, 0, 0, $m, (string)$day['day'], $a); + $maxb = max($maxb, (string)$day['visits']); + $maxp = max($maxp, (string)$day['views']); + $maxv = max($maxv, (string)$day['visitors']); + $s[$time]['book'] = $day['visits']; + $s[$time]['page'] = $day['views']; + $s[$time]['visit'] = $day['visitors']; + $s[$time]['time'] = $time; + } + $max = max($maxb, $maxv); + self::getQ($bid, $max, $maxp, $maxpages, $s); + krsort($s); + $max = max($maxv, $maxb, $maxp); + $days = cubeDate::getDays($a, $m); + $space = round((900 - (count($days) * 20)) / (count($days) * 2)); + @unlink($img); + if (!file_exists($img) || filemtime($img) < cubeDate::round(null, 'H')) { + // Création de l'image + $im = imagecreatetruecolor(944, 306); + imagelayereffect($im, IMG_EFFECT_REPLACE); + $trans = imagecolorallocatealpha($im, 244, 244, 241, 0); + imagefill($im, 0, 0, $trans); + imagelayereffect($im, IMG_EFFECT_ALPHABLEND); + $i = 1; + $x0 = 0; + $y0 = 305; + $h = 300; + $c0 = imagecolorallocate($im, 0, 0 , 0); + $c1 = imagecolorallocatealpha($im, 81, 78, 73, 64); + $hp = $h * ($maxp / $max)-2; + $mhp = $y0 - $hp-6; + imagesetstyle($im, array($c1, $c1, $c1, $c1, $c1, $trans, $trans, $trans, $trans)); + imageline($im, 0, $y0 - $hp, 944, $y0 - $hp, IMG_COLOR_STYLED); + $c1 = imagecolorallocate($im, 81, 78, 73); + $c2 = imagecolorallocatealpha($im, 245, 77, 0, 64); + $hb = $h * ($maxb / $max)-1; + $mhb = $y0 - $hb-6; + imagesetstyle($im, array($c2, $c2, $c2, $c2, $c2, $trans, $trans, $trans, $trans)); + imageline($im, 0, $y0 - $hb, 944, $y0 - $hb, IMG_COLOR_STYLED); + $c2 = imagecolorallocate($im, 245, 77, 0); + $c3 = imagecolorallocatealpha($im, 194, 211, 19, 32); + $hv = $h * ($maxv / $max); + $mhv = $y0 - $hv-6; + imagesetstyle($im, array($c3, $c3, $c3, $c3, $c3, $trans, $trans, $trans, $trans)); + imageline($im, 0, $y0 - $hv, 944, $y0 - $hv, IMG_COLOR_STYLED); + $c3 = imagecolorallocate($im, 194, 211, 19); + foreach($days as $d => $t) { + if (isset($s[$t])) { + $x0 += $space; + $hp = $h * ($s[$t]['page'] / $max)-2; + $hb = $h * ($s[$t]['book'] / $max)-1; + $hv = $h * ($s[$t]['visit'] / $max); + imagefilledrectangle($im, $x0 + 14, $y0 - $hp, $x0, $y0, $c1); + imagerectangle($im, $x0 + 14, $y0 - $hp, $x0, $y0, $c0); + $x0 += 3; + imagefilledrectangle($im, $x0 + 14, $y0 - $hb, $x0, $y0, $c2); + imagerectangle($im, $x0 + 14, $y0 - $hb, $x0, $y0, $c0); + $x0 += 3; + imagefilledrectangle($im, $x0 + 14, $y0 - $hv, $x0, $y0, $c3); + imagerectangle($im, $x0 + 14, $y0 - $hv, $x0, $y0, $c0); + $i++; + $x0 += 14 + $space; + } else { + $x0 += 20 + $space * 2; + } + } + + imageline($im, 0 , $y0, 944 , $y0 , $c0); + imagepng($im, $img); + } + $res = '
' . $maxpages . '
'; + $res .= '
' . $maxb . '
'; + $res .= '
' . $maxv . '
'; + $res .= '' . __('Statistiques mensuelles') . ''; + $res .= ''; + foreach($days as $d => $t) { + $res .= ''; + } + $spacef = 944 - (count($days) * (20 + ($space * 2))); + $res .= ''; + $res .= '
' . $d . '' . cubeMedia::spacer($spacef, 20) . '
'; + $res .= ''; + $res .= ''; + $res .= ''; + $res .= ''; + $res .= '
' . __('Pages vues') . '' . __('Visites') . '' . __('Visiteurs uniques') . '
'; + return $res; + } +} + +?> \ No newline at end of file diff --git a/swf/_src/assets/chapters-back.png b/swf/_src/assets/chapters-back.png new file mode 100644 index 0000000000000000000000000000000000000000..02428407e787aae9be906da54eee6db80d6fb3ad GIT binary patch literal 492 zcmeAS@N?(olHy`uVBq!ia0y~yU|IlVD{`;_Nj87Ui9kxS#5JNMI6tkVJh3R1!7(L2 zDOJHUH!(dmC^a#qvhZZ84FdyXpQnpsNX4x;clLWZ6-uxr{BO8$h1JB=QnHNIak5`r z%LCRcw9bL7-(HzsM2IL!W2QV~?|`+E!lmvvNyhXy{`P zbED2XF25$0F*7jy%ae|D*{Ae=;?sv`pIv0w+il}^?h6~k0nRnb{1c}?X1vwuqs%PJ z$PmyRnIdv?OPRcl^n3<}D;nFM1;;(%%+QZ}&U?O!i6LNpjoBA1e~078)EO99pFER! z&hYiBH3P#^o}z}hSBwk|PI^TRWnUN=92B4H$}%tnOk(6>Xnuxd|)`C zfr$ZxF%*FmUa@d6&thO$Fk!yT0&QEMaVNCcU-)|u+`S*72@Hu-twelQY5xF5AA_f>pUXO@ GgeCxUb*xbU literal 0 HcmV?d00001 diff --git a/swf/_src/assets/chapters-book-over.png b/swf/_src/assets/chapters-book-over.png new file mode 100644 index 0000000000000000000000000000000000000000..0daa3aad1b5e04cb3d3fcd4f1bd24fd61436078a GIT binary patch literal 2931 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 literal 0 HcmV?d00001 diff --git a/swf/_src/assets/chapters-grip.png b/swf/_src/assets/chapters-grip.png new file mode 100644 index 0000000000000000000000000000000000000000..1a70c67b931b80ecad6b4a7bd499c7ecfee8fdca GIT binary patch literal 199 zcmeAS@N?(olHy`uVBq!ia0vp^d_XMB!3HE3FxX51Qj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS>JiZVT2978H@C0SH|%V89-XSn$P|NnG`#H1q*O#E{8b$|Xp zKR2^rcc+wgb7PBvqBjzFh2kM zGyAeh|L?#568FZ{_kFD28MXG^;XQNDrkyOX@Y$pzT+i^LV_RlhYXZf|(L@weeW z&;9rR|6M81@M7Pa_seaD0P>{-tq zr){q6xa`|0Y8w0XejV(@hJ Kb6Mw<&;$S(0_FPv literal 0 HcmV?d00001 diff --git a/swf/_src/assets/chapters-moins.png b/swf/_src/assets/chapters-moins.png new file mode 100644 index 0000000000000000000000000000000000000000..4b48d93015ace960c6e9bdf8eb982edcf078b092 GIT binary patch literal 954 zcmV;r14aCaP)l8y?5PRl?)Bt zETky3LV{W_3b#Vgr+TkH$w%LO_HRg`hYA*oA`A(nz?E?A%L+H!&2{g5bmrsUoqN~2 zEvp0P&fJ+Z=QrnbhCpj0vA)x0^9w^@^({;eQqSVz;^6G;>?C81P)a)nmHfF}ZbFWC zcXvN{p65?ZO|9WCmCJEp3D#RGl^)~9ea^Y)j#%Ws(P(U}tgKu`*`BSO9Hf?(mL`$u z0JRdn@1F?a;YGDteU9=6r1b*LWOMWR{0#PKAq1RMLj@q4%@)ST$NK|7*MNGc*?`Sl zt^S6Mk8feG@g8Ms5C_r^w^u!qbm4fj3%O`XL57VTppb;h%%R41SO+h3ycf_ed_=+xkNL7GD1D=>K z#;KK)#L8AZFFG};)QA}%6*QuK8rzm5E%&4Lr|Y%_#(CM*)d z9M~w449NA#q<~DiAO6<%!|I~_!;Swq1S25aDr>sX51+|l&@o+aW6g;M3df4?1NAA~ zzxx12M$Uml95pY~MD-XgziN_X-c8Wk*7(jIa49$Bg}Au~-Y(0u32Ho?hWYns zhI~kwOa{v3@>6_N9jaT-I#d>EY++&HQKeGZ6erZSwzgL1=H{kR_ON_6*%t5&=xL-u zGj_Xpn}*>aO^GCL@rt3kw50v$m7r-uso>Fbj3$FYn)1N(EMC`%0qHT(OO6T14KdTJ cxcVo+02}$cOnrf>eEuZA@iqtS@e3vF!&T7Go)FUTJuDs(E+?( zIY=6)EOMv8rlzJKxuXE6%bUymz|=+V4Mr+F(fL(5fK%u+k_Kc~O|2__;c!3TZqDFcb<4 zURvMTiKEsH+m!qrC8j)3ZWIg3TyUrU9&~ne3r*69tt~=4v0`h_WL!inJxhM6twiDv z@cRSM(Iy4#Z0|;aGz7aT=>%Ej+ENy%q04GUq2PAA;G?E?_@px`G)Q0)uVe7?_c_q= zxq{{`jpDkY7c7#^W?*?`4tyRze2Dvypr1wh(ARw^=&GGn7-N?JD$F7yJydrKdL9m7 zP{_ovzOf8*i__wOGld#`n4-+q>XKHN-T?c(c*d*8<3pY&f>)$J+-qj$dpLTN6mBAT9q#gvOsmC*sKQrZDIgnWrOYqeNb0-10r3$sF^e@EzhWgXNrVRQ7;m{ zFgJ(R)(Fx*5;UpfH?XkyBL?HELJ(P1tb*x1#Yvv4oXBM`mGI?pE%s_j0Et9;G01L+ zgPlP|{3hoP5CF$WLuHa^U!qX4wdHdgVvAn@^Hc;%j;*VNZxn6Cpir6C;wz9vvr{_R z+KvnJF{MAc=VF>FxiLs=#^Bj^x-jpby9u#wX^^S?#qONjMWD2cD+X#xiD-kWKoBzN z6X4D+f=d&b#wq5%m^=j4&N(ZXo`QnQtRdgacZv9_ZCJ@?I?AVPe8RUHG4PO&@ye#h z{u)iBiTfu*U%~9$3)oNYf=*g4=RW*wk08^NS-H1!@cF!cXuzuXsAmW?T|1Z3V~K<< zRhn+FFBPjbHFfa$;L~&WE=}_65^Lr5)bM&RaY=5NXX<_ vbu~)+6{f(sRS&?f2&k#1p{~Mt{}o^W8=EheQD&)x00000NkvXXu0mjff(Xvi literal 0 HcmV?d00001 diff --git a/swf/_src/assets/chapters-page-field.png b/swf/_src/assets/chapters-page-field.png new file mode 100644 index 0000000000000000000000000000000000000000..8a39d645e64d29b95be6ab9ce525b1b84a493887 GIT binary patch literal 392 zcmV;30eAk1P)>Tfh$m9HnAk(686To5$NZQD!;AvMIZEKwZCH$f1%P1D>9ocU>*UPe*G9LHgXVMq-?qI{GS zAZu(-3BvF^&!q{dCcvCfeu7}8Y5qJRRVDW0QCWf=fHZ`L&=49zLud#Mp&|YeVw&f9 zR53it(I@36h>u|yo&cg81afaFKh@LMwrw9!j7Bu2EA)z$?BQ|Y@95Z%bzN^LKmYUF m;lY*yL-?XW?0-AH1sDKyQBCrFu$wRd0000KaP)jIc6$Q?ax1kO zqJe-CVgijA4OKz{Px@-~C-KM|j|TsOnE2o&Bp8)o&;-%6pcK5IhKj8%-JKcFTz0!% zC^Wz%XXothnfcCrhQR(oJafInEzdQ9Yu+d1L-J2gPq&PZkM~nbiDg-Jg9`b0Jl-ex z?d|PV!!XRj!NDbbwZv~PumB5XGMW3haF;R0k4LoXy<9G@%+1YR#=Q-!<=(Ct$_wWG#X8HcXv11fB_9^pk+;N z;e7rNtbAOAo!n0mpSl2yfB|i7U2v&y7{cKO={iD)FO^EQ%+Ai{Y(Qx#y1?&V{Cepr zlu88<7ULoeIhRoDYI2t&>O5pd-53g&TQVY~_59iEPM9M-j$2t>mb$AT?egoFOtitm91uaj!nSWrN z)&yjfRaLRF3ZSjE3k)M9zsEWfQjWV^#E)nhwE;P;QrKx5tfB~IRLfyJ9k(CeD{2B# zOLZrV4kU+0A>MUfS`!XO9GS+3W|$nm3qGF@Ha64f-dD&&2_`sdxDO zerRrPm3&|C6?nV6aHNs7UCJu8XIUl$gP}uRwO205LO-Bi*9mAbm7K^wpML~hv4l+2 zcVy3G4D#EAqJ1MmF^)rTnIc0LJq~W?0vYQ!6Vx#0x$^k55V|cUp!YO>v4dO7L z)&#UvwQ0B3e#Lajmd6qBbB?nu!e};YRpZ*afF! z$@nOj3D?;i5aw!Ys?oQ1#4+ip>bIWZt4Rv9FOY>72YinzdCnhFFaPM|;Z*qIU(4c3KS~MRx#@*CO2jNO2af;_Om4qkV zmtFxH))cfaJtr6<8H6i~dZymKPBe&LXD>M+Ak#$kEc5EW00RIL!Pa~wL(yyi0000< KMNUMnLSTZUTF}7& literal 0 HcmV?d00001 -- 2.39.5