Overview
Comment:Débuts upload fichier
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 00cedbfb6a0044a3a2ef4520a9f273a6fe9c5a44
User & Date: bohwaz on 2015-02-04 06:29:22
Other Links: manifest | tags
Context
2015-02-04
06:44
Renommage/déplacement du JS et utilisation de l'objet Garradin check-in: 5bd2724e7e user: bohwaz tags: trunk
06:29
Débuts upload fichier check-in: 00cedbfb6a user: bohwaz tags: trunk
06:28
Unification/simplification du Javascript check-in: 9c55662f07 user: bohwaz tags: trunk
Changes

Added doc/dev/fichiers.skriv version [1dfce7dbea].



















>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
= Les fichiers dans le code de Garradin =

== Stockage ==

Pour minimiser les ressources (espace disque, temps processeur), le contenu du fichier est stocké séparé des méta-données du fichier. Ainsi un fichier peut être uploadé plusieurs fois, à plusieurs endroits différents, et n'être stocké qu'une seule fois. De même le cache ne stocke qu'une seule fois le fichier, quel que soit le nombre d'occurrences.

== Upload ==

L'envoi de fichier utilise l'API javascript File pour lire les données du fichier avant envoi. Cela permet de vérifier que la taille du fichier rentre dans les clous. Mais on fait aussi un appel XHR avec le SHA1 du fichier (on utilise https://github.com/srijs/rusha pour ça) pour savoir s'il n'est pas déjà stocké. S'il est déjà stocké ça ne sert à rien de l'envoyer et gaspiller de la bande passante ou du processeur.

Modified src/include/data/0.7.0.sql from [17a1af7af0] to [cbca4aa3a3].

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30


31
32


33
34
35
36
37
38
39
(
    id INTEGER NOT NULL PRIMARY KEY,
    nom TEXT NOT NULL, -- nom de fichier (par exemple image1234.jpeg)
    type TEXT NOT NULL, -- Type MIME
    image INTEGER NOT NULL DEFAULT 0, -- 1 = image reconnue
    titre TEXT NOT NULL, -- Titre/description
    date TEXT NOT NULL DEFAULT CURRENT_DATE, -- Date d'ajout ou mise à jour du fichier
    hash TEXT NOT NULL, -- Hash SHA1 du contenu du fichier
    taille INTEGER NOT NULL -- Taille en octets
);

CREATE UNIQUE INDEX fichiers_hash ON fichiers (hash);
CREATE INDEX fichiers_titre ON fichiers (titre);
CREATE INDEX fichiers_date ON fichiers (date);

CREATE TABLE fichiers_contenu
-- Contenu des fichiers
(
    id INTEGER NOT NULL PRIMARY KEY REFERENCES fichiers (id),


    contenu BLOB
);



CREATE TABLE fichiers_membres
-- Associations entre fichiers et membres (photo de profil par exemple)
(
    fichier INTEGER NOT NULL REFERENCES fichiers (id),
    id INTEGER NOT NULL REFERENCES membres (id),
    PRIMARY KEY(fichier, id)







<
|


<






|
>
>


>
>







12
13
14
15
16
17
18

19
20
21

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
(
    id INTEGER NOT NULL PRIMARY KEY,
    nom TEXT NOT NULL, -- nom de fichier (par exemple image1234.jpeg)
    type TEXT NOT NULL, -- Type MIME
    image INTEGER NOT NULL DEFAULT 0, -- 1 = image reconnue
    titre TEXT NOT NULL, -- Titre/description
    date TEXT NOT NULL DEFAULT CURRENT_DATE, -- Date d'ajout ou mise à jour du fichier

    id_contenu INTEGER NOT NULL REFERENCES fichiers_contenu (id)
);


CREATE INDEX fichiers_titre ON fichiers (titre);
CREATE INDEX fichiers_date ON fichiers (date);

CREATE TABLE fichiers_contenu
-- Contenu des fichiers
(
    id INTEGER NOT NULL PRIMARY KEY,
    hash TEXT NOT NULL, -- Hash SHA1 du contenu du fichier
    taille INTEGER NOT NULL, -- Taille en octets
    contenu BLOB
);

CREATE UNIQUE INDEX fichiers_hash ON fichiers_contenu (hash);

CREATE TABLE fichiers_membres
-- Associations entre fichiers et membres (photo de profil par exemple)
(
    fichier INTEGER NOT NULL REFERENCES fichiers (id),
    id INTEGER NOT NULL REFERENCES membres (id),
    PRIMARY KEY(fichier, id)

Modified src/include/data/schema.sql from [55e42ab66a] to [52605cc884].

329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347


348
349


350
351
352
353
354
355
356
(
    id INTEGER NOT NULL PRIMARY KEY,
    nom TEXT NOT NULL, -- nom de fichier (par exemple image1234.jpeg)
    type TEXT NOT NULL, -- Type MIME
    image INTEGER NOT NULL DEFAULT 0, -- 1 = image reconnue
    titre TEXT NOT NULL, -- Titre/description
    date TEXT NOT NULL DEFAULT CURRENT_DATE, -- Date d'ajout ou mise à jour du fichier
    hash TEXT NOT NULL, -- Hash SHA1 du contenu du fichier
    taille INTEGER NOT NULL -- Taille en octets
);

CREATE UNIQUE INDEX fichiers_hash ON fichiers (hash);
CREATE INDEX fichiers_titre ON fichiers (titre);
CREATE INDEX fichiers_date ON fichiers (date);

CREATE TABLE fichiers_contenu
-- Contenu des fichiers
(
    id INTEGER NOT NULL PRIMARY KEY REFERENCES fichiers (id),


    contenu BLOB
);



CREATE TABLE fichiers_membres
-- Associations entre fichiers et membres (photo de profil par exemple)
(
    fichier INTEGER NOT NULL REFERENCES fichiers (id),
    id INTEGER NOT NULL REFERENCES membres (id),
    PRIMARY KEY(fichier, id)







<
|


<






|
>
>


>
>







329
330
331
332
333
334
335

336
337
338

339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
(
    id INTEGER NOT NULL PRIMARY KEY,
    nom TEXT NOT NULL, -- nom de fichier (par exemple image1234.jpeg)
    type TEXT NOT NULL, -- Type MIME
    image INTEGER NOT NULL DEFAULT 0, -- 1 = image reconnue
    titre TEXT NOT NULL, -- Titre/description
    date TEXT NOT NULL DEFAULT CURRENT_DATE, -- Date d'ajout ou mise à jour du fichier

    id_contenu INTEGER NOT NULL REFERENCES fichiers_contenu (id)
);


CREATE INDEX fichiers_titre ON fichiers (titre);
CREATE INDEX fichiers_date ON fichiers (date);

CREATE TABLE fichiers_contenu
-- Contenu des fichiers
(
    id INTEGER NOT NULL PRIMARY KEY,
    hash TEXT NOT NULL, -- Hash SHA1 du contenu du fichier
    taille INTEGER NOT NULL, -- Taille en octets
    contenu BLOB
);

CREATE UNIQUE INDEX fichiers_hash ON fichiers_contenu (hash);

CREATE TABLE fichiers_membres
-- Associations entre fichiers et membres (photo de profil par exemple)
(
    fichier INTEGER NOT NULL REFERENCES fichiers (id),
    id INTEGER NOT NULL REFERENCES membres (id),
    PRIMARY KEY(fichier, id)

Modified src/include/lib/Garradin/Fichiers.php from [c00d51886f] to [9f13370bd2].

18
19
20
21
22
23
24




25
26
27
28
29
30
31
	public $type;
	public $titre;
	public $nom;
	public $date;
	public $hash;
	public $taille;
	public $id;





	public function __construct($id)
	{
		$data = DB::getInstance()->simpleQuerySingle('SELECT *, strftime(\'%s\', date) AS date
			FROM fichiers WHERE id = ?;', true, (int)$id);

		foreach ($data as $key=>$value)







>
>
>
>







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
	public $type;
	public $titre;
	public $nom;
	public $date;
	public $hash;
	public $taille;
	public $id;

	const LIEN_COMPTA = 'compta_journal';
	const LIEN_WIKI = 'wiki_pages';
	const LIEN_MEMBRES = 'membres';

	public function __construct($id)
	{
		$data = DB::getInstance()->simpleQuerySingle('SELECT *, strftime(\'%s\', date) AS date
			FROM fichiers WHERE id = ?;', true, (int)$id);

		foreach ($data as $key=>$value)
40
41
42
43
44
45
46
47
























48
49
50
51
52
53
54
55
56
57
58





59


60

61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

81
82
83
84
85
86
87
88
89
90
91
92
93
	 * @param  integer $height Hauteur
	 * @param  boolean $crop   TRUE si on doit cropper aux dimensions indiquées
	 * @return void
	 */
	public function getThumbnail($width, $height, $crop = false)
	{
	}

























	/**
	 * Supprime l'image
	 * @return boolean TRUE en cas de succès
	 */
	public function remove()
	{
		$db = DB::getInstance();
		$db->exec('BEGIN;');
		$db->simpleExec('DELETE FROM fichiers_compta_journal WHERE fichier = ?;', (int)$this->id);
		$db->simpleExec('DELETE FROM fichiers_wiki_pages WHERE fichier = ?;', (int)$this->id);
		$db->simpleExec('DELETE FROM fichiers_membres WHERE fichier = ?;', (int)$this->id);





		$db->simpleExec('DELETE FROM fichiers_contenu WHERE id = ?;', (int)$this->id);


		$db->simpleExec('DELETE FROM fichiers WHERE id = ?;', (int)$this->id);

		return $db->exec('END;');
	}

	/**
	 * Modifie les informations du fichier
	 * @param  string $titre Le titre du fichier
	 * @param  string $nom   Le nom du fichier (avec extension)
	 * @return boolean TRUE en cas de succès
	 */
	public function edit($titre, $nom)
	{

	}

	/**
	 * Envoie le fichier au client HTTP
	 * @return void
	 */
	public function serve()
	{

		$cache_id = 'fichiers.' . $this->id;

		// Le fichier n'existe pas dans le cache statique, on l'enregistre
		if (!Static_Cache::exists($cache_id))
		{
			$blob = DB::getInstance()->openBlob('fichiers_contenu', 'contenu', (int)$this->id);
			Static_Cache::storeFromPointer($cache_id, $blob);
			fclose($blob);
		}

		$path = Static_Cache::getPath($cache_id);

		// Désactiver le cache








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|









>
>
>
>
>
|
>
>

>




















>
|




|







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
	 * @param  integer $height Hauteur
	 * @param  boolean $crop   TRUE si on doit cropper aux dimensions indiquées
	 * @return void
	 */
	public function getThumbnail($width, $height, $crop = false)
	{
	}

	public function linkTo($type, $foreign_id)
	{
		$db = DB::getInstance();
		$check = [self::LIEN_MEMBRES, self::LIEN_WIKI, self::LIEN_COMPTA];

		if (!in_array($type, $check))
		{
			throw new \LogicException('Type de lien de fichier inconnu.');
		}

		unset($check[array_search($type, $check)]);
		
		foreach ($check as $check_type)
		{
			if ($db->simpleQuerySingle('SELECT 1 FROM fichiers_' . $check_type . ' WHERE fichier = ?;', false, (int)$this->id))
			{
				throw new \LogicException('Ce fichier est déjà lié à un autre contenu : ' . $check_type);
			}
		}

		return $db->simpleExec('INSERT OR IGNORE INTO fichiers_' . $type . ' (fichier, id) VALUES (?, ?);',
			(int)$this->id, (int)$foreign_id);
	}

	/**
	 * Supprime le fichier
	 * @return boolean TRUE en cas de succès
	 */
	public function remove()
	{
		$db = DB::getInstance();
		$db->exec('BEGIN;');
		$db->simpleExec('DELETE FROM fichiers_compta_journal WHERE fichier = ?;', (int)$this->id);
		$db->simpleExec('DELETE FROM fichiers_wiki_pages WHERE fichier = ?;', (int)$this->id);
		$db->simpleExec('DELETE FROM fichiers_membres WHERE fichier = ?;', (int)$this->id);

		// Suppression du contenu s'il n'est pas utilisé par un autre fichier
		if (!($id_contenu = $db->simpleQuerySingle('SELECT id_contenu FROM fichiers AS f1 INNER JOIN fichiers AS f2 
			ON f1.id_contenu = f2.id_contenu AND f1.id != f2.id WHERE f2.id = ?;', false, (int)$this->id)))
		{
			$db->simpleExec('DELETE FROM fichiers_contenu WHERE id = ?;', (int)$id_contenu);
		}

		$db->simpleExec('DELETE FROM fichiers WHERE id = ?;', (int)$this->id);

		return $db->exec('END;');
	}

	/**
	 * Modifie les informations du fichier
	 * @param  string $titre Le titre du fichier
	 * @param  string $nom   Le nom du fichier (avec extension)
	 * @return boolean TRUE en cas de succès
	 */
	public function edit($titre, $nom)
	{

	}

	/**
	 * Envoie le fichier au client HTTP
	 * @return void
	 */
	public function serve()
	{
		// Le cache est géré par ID contenu, pas ID fichier, pour minimiser l'espace disque utilisé
		$cache_id = 'fichiers.' . $this->id_contenu;

		// Le fichier n'existe pas dans le cache statique, on l'enregistre
		if (!Static_Cache::exists($cache_id))
		{
			$blob = DB::getInstance()->openBlob('fichiers_contenu', 'contenu', (int)$this->id_contenu);
			Static_Cache::storeFromPointer($cache_id, $blob);
			fclose($blob);
		}

		$path = Static_Cache::getPath($cache_id);

		// Désactiver le cache
126
127
128
129
130
131
132















133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168

		ob_clean();
		flush();

		// Sinon on envoie le fichier à la mano
		readfile($path);
	}
















	/**
	 * Upload du fichier par POST
	 * @param  array  $file  Caractéristiques du fichier envoyé
	 * @param  string $titre Titre descriptif du fichier
	 * @return boolean TRUE en cas de succès
	 */
	static public function upload($file, $titre)
	{
		// FIXME traiter les images envoyées redimensionnées par javascript (base64)

		$name = '...';
		// FIXME name sanitization

		if (preg_match('/\.(?:php\d*|cgi|pl|perl|jsp|asp|py|exe|com|bat|vb[se]?|chm|pif|reg|ws[cfh]|scr|asp)$/i', $name))
		{
			throw new UserException('Extension de fichier interdite.');
		}

		$ext = substr($name, strrpos($name, '.')+1);
		$ext = strtolower($ext);

		if (!array_key_exists($ext, $this->allowed_files))
		{
			throw new UserException('Ce type de fichier n\'est pas autorisé.');
		}

		$bytes = file_get_contents($path, false, null, -1, 1024);
		$type = \KD2\FileInfo::guessMimeType($bytes);

		if (!$type)
		{
			throw new UserException('Type de fichier inconnu.');
		}
	}
}







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







|






|







|







|





163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220

		ob_clean();
		flush();

		// Sinon on envoie le fichier à la mano
		readfile($path);
	}

	/**
	 * Vérifie si le hash fourni n'est pas déjà stocké
	 * Utile pour par exemple reconnaître un ficher dont le contenu est déjà stocké, et éviter un nouvel upload
	 * @param  string $hash Hash SHA1
	 * @return boolean      TRUE si le hash est déjà présent dans fichiers_contenu, FALSE sinon
	 */
	static public function checkHash($hash)
	{
		return (boolean) DB::getInstance()->simpleQuerySingle(
			'SELECT 1 FROM fichiers_contenu WHERE hash = ?;', 
			false, 
			trim(strtolower($hash))
		);
	}

	/**
	 * Upload du fichier par POST
	 * @param  array  $file  Caractéristiques du fichier envoyé
	 * @param  string $titre Titre descriptif du fichier
	 * @return boolean TRUE en cas de succès
	 */
	static public function upload($file, $titre, $allow_anything = false)
	{
		// FIXME traiter les images envoyées redimensionnées par javascript (base64)

		$name = '...';
		// FIXME name sanitization

		if (!$allow_anything && preg_match('/\.(?:php\d*|cgi|pl|perl|jsp|asp|py|exe|com|bat|vb[se]?|chm|pif|reg|ws[cfh]|scr|asp)$/i', $name))
		{
			throw new UserException('Extension de fichier interdite.');
		}

		$ext = substr($name, strrpos($name, '.')+1);
		$ext = strtolower($ext);

		if (!$allow_anything && !array_key_exists($ext, $this->allowed_files))
		{
			throw new UserException('Ce type de fichier n\'est pas autorisé.');
		}

		$bytes = file_get_contents($path, false, null, -1, 1024);
		$type = \KD2\FileInfo::guessMimeType($bytes);

		if (!$allow_anything && !$type)
		{
			throw new UserException('Type de fichier inconnu.');
		}
	}
}

Modified src/include/lib/Garradin/Static_Cache.php from [5fabb1fda6] to [80b1dfbb7b].

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
	const CLEAN_EXPIRE = 86400; // 1 day

	protected static function _getCacheDir()
	{
		return CACHE_ROOT . '/static';
	}

	protected static function __getCachePath($id)
	{
		$id = 'cache_' . sha1($id);
		return self::_getCacheDir() . '/' . $id;
	}

	static public function store($id, $content)
	{







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
	const CLEAN_EXPIRE = 86400; // 1 day

	protected static function _getCacheDir()
	{
		return CACHE_ROOT . '/static';
	}

	protected static function _getCachePath($id)
	{
		$id = 'cache_' . sha1($id);
		return self::_getCacheDir() . '/' . $id;
	}

	static public function store($id, $content)
	{

Modified src/include/lib/Garradin/Template.php from [3482f439eb] to [31d36787f2].

602
603
604
605
606
607
608
609
610
611
612
613
614
615

$tpl->register_modifier('format_bytes', function ($size) {
    if ($size > (1024 * 1024))
        return round($size / 1024 / 1024, 2) . ' Mo';
    elseif ($size > 1024)
        return round($size / 1024, 2) . ' Ko';
    else
        return $size . ' ob_get_contents(oid)';
});

$tpl->register_modifier('strftime_fr', 'Garradin\tpl_strftime_fr');
$tpl->register_modifier('date_fr', 'Garradin\tpl_date_fr');

?>







|






602
603
604
605
606
607
608
609
610
611
612
613
614
615

$tpl->register_modifier('format_bytes', function ($size) {
    if ($size > (1024 * 1024))
        return round($size / 1024 / 1024, 2) . ' Mo';
    elseif ($size > 1024)
        return round($size / 1024, 2) . ' Ko';
    else
        return $size . ' o';
});

$tpl->register_modifier('strftime_fr', 'Garradin\tpl_strftime_fr');
$tpl->register_modifier('date_fr', 'Garradin\tpl_date_fr');

?>

Added src/templates/admin/wiki/_fichiers.tpl version [67e6c5be20].









































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{include file="admin/_head.tpl" title="Inclure un fichier" current="wiki" body_id="popup" is_popup=true js=1}

 <form method="post" enctype="multipart/form-data" action="{$self_url|escape}" id="f_upload">
    <fieldset>
        <legend>Téléverser un fichier</legend>
        <input type="hidden" name="MAX_FILE_SIZE" value="{$max_size|escape}" id="f_maxsize" />
        <dl>
            <dt><label for="f_fichier">Sélectionner un fichier</label></dt>
            <dd class="help">Taille maximale : {$max_size|format_bytes}</dd>
            <dd><input type="file" name="fichier" id="f_fichier" /></dd>
            <dt><label for="f_titre">Titre du fichier (description)</label></dt>
            <dd><input type="text" name="titre" id="f_titre" /></dd>
        </dl>
        <p class="submit">
            <input type="submit" id="f_submit" value="Envoyer le fichier" />
        </p>
    </fieldset>
</form>

{include file="admin/_foot.tpl"}

Added src/www/admin/static/scripts/file_upload.js version [8d3bcfe5d7].











































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
(function () {
	if (!FileReader || !File)
		return false;

	var uploadHelper = function ()
	{
		var rusha = new Rusha();
		var form = $('#f_upload');
		var max_size = $('#f_maxsize').value;
		var admin_url = document.body.getAttribute('data-url');

		form.onsubmit = function () {
			return true;
		};

		$('#f_fichier').onchange = function () {
			if (this.files.length < 1)
				return false;

			if (this.files.length > 1)
				return !alert("Vous ne pouvez sélectionner qu'un seul fichier.");

			var file = this.files[0];

			if (file.size > max_size)
			{
				this.value = '';
				return !alert("Ce fichier de " + getByteSize(file.size) 
					+ " dépasse la taille autorisée de " + getByteSize(max_size) + ".\nEnvoi impossible !");
			}

			var name = file.name.replace(/\.[^.]+/g, '');
			name = name.replace(/[_.-]+/g, ' ');
			name = name.replace(/\w/, function (match) { return match.toUpperCase(); });

			document.getElementById('f_titre').value = name;

			// Vérification de l'existence du fichier
			var fr = new FileReader;
			fr.onloadend = function () {
				if (this.error) return false;
				var hash = rusha.digestFromArrayBuffer(fr.result);
				garradin.load('admin/_upload_check.php?hash=' + hash, function (data) {
					if (parseInt(data, 10) == 1)
					{
						alert('ok');
					}
				})
			};
			fr.readAsArrayBuffer(file);
		};
	};

	function getByteSize(size)
	{
		if (size < 1024)
			return size + ' octets';
		else if (size < 1024*1024)
			return Math.round(size / 1024) + ' Ko';
		else
			return (Math.round(size / 1024 / 1024 * 100) / 100) + ' Mo';
	}

	garradin.onload(uploadHelper);
}());


/*! rusha 2015-01-11 */
!function(){function a(a){"use strict";var d={fill:0},f=function(a){for(a+=9;a%64>0;a+=1);return a},g=function(a,b){for(var c=b>>2;c<a.length;c++)a[c]=0},h=function(a,b,c){a[b>>2]|=128<<24-(b%4<<3),a[((b>>2)+2&-16)+15]=c<<3},i=function(a,b,c,d,e){var f,g=this,h=e%4,i=d%4,j=d-i;if(j>0)switch(h){case 0:a[e+3|0]=g.charCodeAt(c);case 1:a[e+2|0]=g.charCodeAt(c+1);case 2:a[e+1|0]=g.charCodeAt(c+2);case 3:a[0|e]=g.charCodeAt(c+3)}for(f=h;j>f;f=f+4|0)b[e+f>>2]=g.charCodeAt(c+f)<<24|g.charCodeAt(c+f+1)<<16|g.charCodeAt(c+f+2)<<8|g.charCodeAt(c+f+3);switch(i){case 3:a[e+j+1|0]=g.charCodeAt(c+j+2);case 2:a[e+j+2|0]=g.charCodeAt(c+j+1);case 1:a[e+j+3|0]=g.charCodeAt(c+j)}},j=function(a,b,c,d,e){var f,g=this,h=e%4,i=d%4,j=d-i;if(j>0)switch(h){case 0:a[e+3|0]=g[c];case 1:a[e+2|0]=g[c+1];case 2:a[e+1|0]=g[c+2];case 3:a[0|e]=g[c+3]}for(f=4-h;j>f;f=f+=4)b[e+f>>2]=g[c+f]<<24|g[c+f+1]<<16|g[c+f+2]<<8|g[c+f+3];switch(i){case 3:a[e+j+1|0]=g[c+j+2];case 2:a[e+j+2|0]=g[c+j+1];case 1:a[e+j+3|0]=g[c+j]}},k=function(a,b,d,e,f){var g,h=this,i=f%4,j=e%4,k=e-j,l=new Uint8Array(c.readAsArrayBuffer(h.slice(d,d+e)));if(k>0)switch(i){case 0:a[f+3|0]=l[0];case 1:a[f+2|0]=l[1];case 2:a[f+1|0]=l[2];case 3:a[0|f]=l[3]}for(g=4-i;k>g;g=g+=4)b[f+g>>2]=l[g]<<24|l[g+1]<<16|l[g+2]<<8|l[g+3];switch(j){case 3:a[f+k+1|0]=l[k+2];case 2:a[f+k+2|0]=l[k+1];case 1:a[f+k+3|0]=l[k]}},l=function(a){switch(e.getDataType(a)){case"string":return i.bind(a);case"array":return j.bind(a);case"buffer":return j.bind(a);case"arraybuffer":return j.bind(new Uint8Array(a));case"view":return j.bind(new Uint8Array(a.buffer,a.byteOffset,a.byteLength));case"blob":return k.bind(a)}},m=function(a){var b,c,d="0123456789abcdef",e=[],f=new Uint8Array(a);for(b=0;b<f.length;b++)c=f[b],e[b]=d.charAt(c>>4&15)+d.charAt(c>>0&15);return e.join("")},n=function(a){var b;if(65536>=a)return 65536;if(16777216>a)for(b=1;a>b;b<<=1);else for(b=16777216;a>b;b+=16777216);return b},o=function(a){if(a%64>0)throw new Error("Chunk size must be a multiple of 128 bit");d.maxChunkLen=a,d.padMaxChunkLen=f(a),d.heap=new ArrayBuffer(n(d.padMaxChunkLen+320+20)),d.h32=new Int32Array(d.heap),d.h8=new Int8Array(d.heap),d.core=b({Int32Array:Int32Array,DataView:DataView},{},d.heap),d.buffer=null};o(a||65536);var p=function(a,b){var c=new Int32Array(a,b+320,5);c[0]=1732584193,c[1]=-271733879,c[2]=-1732584194,c[3]=271733878,c[4]=-1009589776},q=function(a,b){var c=f(a),e=new Int32Array(d.heap,0,c>>2);return g(e,a),h(e,a,b),c},r=function(a,b,c){l(a)(d.h8,d.h32,b,c,0)},s=function(a,b,c,e,f){var g=c;f&&(g=q(c,e)),r(a,b,c),d.core.hash(g,d.padMaxChunkLen)},t=function(a,b){var c=new Int32Array(a,b+320,5),d=new Int32Array(5),e=new DataView(d.buffer);return e.setInt32(0,c[0],!1),e.setInt32(4,c[1],!1),e.setInt32(8,c[2],!1),e.setInt32(12,c[3],!1),e.setInt32(16,c[4],!1),d},u=this.rawDigest=function(a){var b=a.byteLength||a.length||a.size;p(d.heap,d.padMaxChunkLen);var c=0,e=d.maxChunkLen;for(c=0;b>c+e;c+=e)s(a,c,e,b,!1);return s(a,c,b-c,b,!0),t(d.heap,d.padMaxChunkLen)};this.digest=this.digestFromString=this.digestFromBuffer=this.digestFromArrayBuffer=function(a){return m(u(a).buffer)}}function b(a,b,c){"use asm";function d(a,b){a|=0,b|=0;var c=0,d=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;for(f=e[b+320>>2]|0,h=e[b+324>>2]|0,j=e[b+328>>2]|0,l=e[b+332>>2]|0,n=e[b+336>>2]|0,c=0;(c|0)<(a|0);c=c+64|0){for(g=f,i=h,k=j,m=l,o=n,d=0;(d|0)<64;d=d+4|0)q=e[c+d>>2]|0,p=((f<<5|f>>>27)+(h&j|~h&l)|0)+((q+n|0)+1518500249|0)|0,n=l,l=j,j=h<<30|h>>>2,h=f,f=p,e[a+d>>2]=q;for(d=a+64|0;(d|0)<(a+80|0);d=d+4|0)q=(e[d-12>>2]^e[d-32>>2]^e[d-56>>2]^e[d-64>>2])<<1|(e[d-12>>2]^e[d-32>>2]^e[d-56>>2]^e[d-64>>2])>>>31,p=((f<<5|f>>>27)+(h&j|~h&l)|0)+((q+n|0)+1518500249|0)|0,n=l,l=j,j=h<<30|h>>>2,h=f,f=p,e[d>>2]=q;for(d=a+80|0;(d|0)<(a+160|0);d=d+4|0)q=(e[d-12>>2]^e[d-32>>2]^e[d-56>>2]^e[d-64>>2])<<1|(e[d-12>>2]^e[d-32>>2]^e[d-56>>2]^e[d-64>>2])>>>31,p=((f<<5|f>>>27)+(h^j^l)|0)+((q+n|0)+1859775393|0)|0,n=l,l=j,j=h<<30|h>>>2,h=f,f=p,e[d>>2]=q;for(d=a+160|0;(d|0)<(a+240|0);d=d+4|0)q=(e[d-12>>2]^e[d-32>>2]^e[d-56>>2]^e[d-64>>2])<<1|(e[d-12>>2]^e[d-32>>2]^e[d-56>>2]^e[d-64>>2])>>>31,p=((f<<5|f>>>27)+(h&j|h&l|j&l)|0)+((q+n|0)-1894007588|0)|0,n=l,l=j,j=h<<30|h>>>2,h=f,f=p,e[d>>2]=q;for(d=a+240|0;(d|0)<(a+320|0);d=d+4|0)q=(e[d-12>>2]^e[d-32>>2]^e[d-56>>2]^e[d-64>>2])<<1|(e[d-12>>2]^e[d-32>>2]^e[d-56>>2]^e[d-64>>2])>>>31,p=((f<<5|f>>>27)+(h^j^l)|0)+((q+n|0)-899497514|0)|0,n=l,l=j,j=h<<30|h>>>2,h=f,f=p,e[d>>2]=q;f=f+g|0,h=h+i|0,j=j+k|0,l=l+m|0,n=n+o|0}e[b+320>>2]=f,e[b+324>>2]=h,e[b+328>>2]=j,e[b+332>>2]=l,e[b+336>>2]=n}var e=new a.Int32Array(c);return{hash:d}}if("undefined"!=typeof module?module.exports=a:"undefined"!=typeof window&&(window.Rusha=a),"undefined"!=typeof FileReaderSync){var c=new FileReaderSync,d=new a(4194304);self.onmessage=function(a){var b,c=a.data.data;try{b=d.digest(c),self.postMessage({id:a.data.id,hash:b})}catch(e){self.postMessage({id:a.data.id,error:e.name})}}}var e={getDataType:function(a){if("string"==typeof a)return"string";if(a instanceof Array)return"array";if("undefined"!=typeof global&&global.Buffer&&global.Buffer.isBuffer(a))return"buffer";if(a instanceof ArrayBuffer)return"arraybuffer";if(a.buffer instanceof ArrayBuffer)return"view";if(a instanceof Blob)return"blob";throw new Error("Unsupported data type.")}}}();

Added src/www/admin/wiki/_fichiers.php version [219fbf114c].





























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?php
namespace Garradin;

require_once __DIR__ . '/_inc.php';

if ((trim(Utils::get('page')) == '') || !is_numeric(Utils::get('page')))
{
    throw new UserException('Numéro de page invalide.');
}

$page = $wiki->getById(Utils::get('page'));
$error = false;

if (!$page)
{
    throw new UserException('Page introuvable.');
}

if (Utils::post('submit'))
{
    if (!Utils::CSRF_check('file_upload_'.$page['id']))
    {
        $error = 'Une erreur est survenue, merci de renvoyer le formulaire.';
    }
    else
    {
        try {
            $fichier = Fichiers::upload($_FILES['fichier'], Utils::post('titre'));
            $fichier->link(Fichiers::LIEN_WIKI, $page['id']);

            Utils::redirect('/admin/wiki/_fichiers.php?ok');
        }
        catch (UserException $e)
        {
            $error = $e->getMessage();
        }
    }
}

$tpl->assign('max_size', Utils::getMaxUploadSize());
$tpl->assign('error', $error);
$tpl->assign('sent', isset($_GET['sent']) ? true : false);

$tpl->assign('custom_js', ['scripts/file_upload.js']);

$tpl->display('admin/wiki/_fichiers.tpl');