forked from moodle/moodle
-
Notifications
You must be signed in to change notification settings - Fork 0
/
bakerlib.php
141 lines (123 loc) · 4.92 KB
/
bakerlib.php
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
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
131
132
133
134
135
136
137
138
139
140
141
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Baking badges library.
*
* @package core
* @subpackage badges
* @copyright 2012 onwards Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @author Yuliya Bozhko <yuliya.bozhko@totaralms.com>
*/
defined('MOODLE_INTERNAL') || die();
/**
* Information on PNG file chunks can be found at http://www.w3.org/TR/PNG/#11Chunks
* Some other info on PNG that I used http://garethrees.org/2007/11/14/pngcrush/
*
* Example of use:
* $png = new PNG_MetaDataHandler('file.png');
*
* if ($png->check_chunks("tEXt", "openbadge")) {
* $newcontents = $png->add_chunks("tEXt", "openbadge", 'http://some.public.url/to.your.assertion.file');
* }
*
* file_put_contents('file.png', $newcontents);
*/
class PNG_MetaDataHandler
{
/** @var string File content as a string */
private $_contents;
/** @var int Length of the image file */
private $_size;
/** @var array Variable for storing parsed chunks */
private $_chunks;
/**
* Prepares file for handling metadata.
* Verifies that this file is a valid PNG file.
* Unpacks file chunks and reads them into an array.
*
* @param string $contents File content as a string
*/
public function __construct($contents) {
$this->_contents = $contents;
$png_signature = pack("C8", 137, 80, 78, 71, 13, 10, 26, 10);
// Read 8 bytes of PNG header and verify.
$header = substr($this->_contents, 0, 8);
if ($header != $png_signature) {
debugging('This is not a valid PNG image');
}
$this->_size = strlen($this->_contents);
$this->_chunks = array();
// Skip 8 bytes of IHDR image header.
$position = 8;
do {
$chunk = @unpack('Nsize/a4type', substr($this->_contents, $position, 8));
$this->_chunks[$chunk['type']][] = substr($this->_contents, $position + 8, $chunk['size']);
// Skip 12 bytes chunk overhead.
$position += $chunk['size'] + 12;
} while ($position < $this->_size);
}
/**
* Checks if a key already exists in the chunk of said type.
* We need to avoid writing same keyword into file chunks.
*
* @param string $type Chunk type, like iTXt, tEXt, etc.
* @param string $check Keyword that needs to be checked.
*
* @return boolean (true|false) True if file is safe to write this keyword, false otherwise.
*/
public function check_chunks($type, $check) {
if (array_key_exists($type, $this->_chunks)) {
foreach (array_keys($this->_chunks[$type]) as $typekey) {
list($key, $data) = explode("\0", $this->_chunks[$type][$typekey]);
if (strcmp($key, $check) == 0) {
debugging('Key "' . $check . '" already exists in "' . $type . '" chunk.');
return false;
}
}
}
return true;
}
/**
* Adds a chunk with keyword and data to the file content.
* Chunk is added to the end of the file, before IEND image trailer.
*
* @param string $type Chunk type, like iTXt, tEXt, etc.
* @param string $key Keyword that needs to be added.
* @param string $value Currently an assertion URL that is added to an image metadata.
*
* @return string $result File content with a new chunk as a string. Can be used in file_put_contents() to write to a file.
*/
public function add_chunks($type, $key, $value) {
if (strlen($key) > 79) {
debugging('Key is too big');
}
// tEXt Textual data.
// Keyword: 1-79 bytes (character string)
// Null separator: 1 byte
// Text: n bytes (character string)
$data = $key . "\0" . $value;
$crc = pack("N", crc32($type . $data));
$len = pack("N", strlen($data));
// Chunk format: length + type + data + CRC.
// CRC is a CRC-32 computed over the chunk type and chunk data.
$newchunk = $len . $type . $data . $crc;
$result = substr($this->_contents, 0, $this->_size - 12)
. $newchunk
. substr($this->_contents, $this->_size - 12, 12);
return $result;
}
}