Passed
Push — 1.11.x ( bce6cd...c146d9 )
by Angel Fernando Quiroz
12:25
created

common_cartridge/export/src/utils/CcHelpers.php (2 issues)

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
abstract class CcHelpers
5
{
6
    /**
7
     * Checks extension of the supplied filename.
8
     *
9
     * @param string $filename
10
     */
11
    public static function isHtml($filename)
12
    {
13
        $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
14
15
        return in_array($extension, ['htm', 'html']);
16
    }
17
18
    /**
19
     * Generates unique identifier.
20
     *
21
     * @param string $prefix
22
     * @param string $suffix
23
     *
24
     * @return string
25
     */
26
    public static function uuidgen($prefix = '', $suffix = '', $uppercase = true)
27
    {
28
        $uuid = trim(sprintf('%s%04x%04x%s', $prefix, mt_rand(0, 65535), mt_rand(0, 65535), $suffix));
29
        $result = $uppercase ? strtoupper($uuid) : strtolower($uuid);
30
31
        return $result;
32
    }
33
34
    /**
35
     * Creates new folder with random name.
36
     *
37
     * @param string $where
38
     * @param string $prefix
39
     * @param string $suffix
40
     *
41
     * @return mixed - directory short name or false in case of failure
42
     */
43
    public static function randomdir($where, $prefix = '', $suffix = '')
44
    {
45
        $permDirs = api_get_permissions_for_new_directories();
46
47
        $dirname = false;
48
        $randomname = self::uuidgen($prefix, $suffix, false);
49
        $newdirname = $where.DIRECTORY_SEPARATOR.$randomname;
50
        if (mkdir($newdirname)) {
51
            chmod($newdirname, $permDirs);
52
            $dirname = $randomname;
53
        }
54
55
        return $dirname;
56
    }
57
58
    public static function buildQuery($attributes, $search)
59
    {
60
        $result = '';
61
        foreach ($attributes as $attribute) {
62
            if ($result != '') {
63
                $result .= ' | ';
64
            }
65
            $result .= "//*[starts-with(@{$attribute},'{$search}')]/@{$attribute}";
66
        }
67
68
        return $result;
69
    }
70
71
    public static function processEmbeddedFiles(&$doc, $attributes, $search, $customslash = null)
72
    {
73
        $result = [];
74
        $query = self::buildQuery($attributes, $search);
75
        $list = $doc->nodeList($query);
76
        foreach ($list as $filelink) {
77
            $rvalue = str_replace($search, '', $filelink->nodeValue);
78
            if (!empty($customslash)) {
79
                $rvalue = str_replace($customslash, '/', $rvalue);
80
            }
81
            $result[] = rawurldecode($rvalue);
82
        }
83
84
        return $result;
85
    }
86
87
    /**
88
     * Get list of embedded files.
89
     *
90
     * @param string $html
91
     *
92
     * @return multitype:mixed
93
     */
94
    public static function embeddedFiles($html)
95
    {
96
        $result = [];
97
        $doc = new XMLGenericDocument();
98
        $doc->doc->validateOnParse = false;
99
        $doc->doc->strictErrorChecking = false;
100
        if (!empty($html) && $doc->loadHTML($html)) {
101
            $attributes = ['src', 'href'];
102
            $result1 = self::processEmbeddedFiles($doc, $attributes, '@@PLUGINFILE@@');
103
            $result2 = self::processEmbeddedFiles($doc, $attributes, '$@FILEPHP@$', '$@SLASH@$');
104
            $result = array_merge($result1, $result2);
105
        }
106
107
        return $result;
108
    }
109
110
    public static function embeddedMapping($packageroot, $contextid = null, $folder = null, $docfilepath = null)
111
    {
112
        if (isset($folder)) {
113
            $files = array_diff(scandir($folder), ['.', '..']);
114
        } else {
115
            $folder = dirname($docfilepath);
116
            $files[] = basename($docfilepath);
0 ignored issues
show
Comprehensibility Best Practice introduced by
$files was never initialized. Although not strictly required by PHP, it is generally a good practice to add $files = array(); before regardless.
Loading history...
117
        }
118
119
        $depfiles = [];
120
        foreach ($files as $file) {
121
            $mainfile = 1;
122
            $filename = $file;
123
            $filepath = DIRECTORY_SEPARATOR;
124
            $source = '';
125
            $author = '';
126
            $license = '';
127
            $hashedname = '';
128
            $hashpart = '';
129
130
            $location = $folder.DIRECTORY_SEPARATOR.$file;
131
            $type = mime_content_type($file);
132
133
            $depfiles[$filepath.$filename] = [$location,
134
                                                    ($mainfile == 1),
135
                                                    strtolower(str_replace(' ', '_', $filename)),
136
                                                    $type,
137
                                                    $source,
138
                                                    $author,
139
                                                    $license,
140
                                                    strtolower(str_replace(' ', '_', $filepath)), ];
141
        }
142
143
        return $depfiles;
144
    }
145
146
    public static function addFiles(CcIManifest &$manifest, $packageroot, $outdir, $allinone = true, $folder = null, $docfilepath = null)
147
    {
148
        $permDirs = api_get_permissions_for_new_directories();
149
150
        $files = CcHelpers::embeddedMapping($packageroot, null, $folder, $docfilepath);
151
152
        $rdir = $allinone ? new CcResourceLocation($outdir) : null;
153
        foreach ($files as $virtual => $values) {
154
            $clean_filename = $values[2];
155
            if (!$allinone) {
156
                $rdir = new CcResourceLocation($outdir);
157
            }
158
            $rtp = $rdir->fullpath().$values[7].$clean_filename;
159
            //Are there any relative virtual directories?
160
            //let us try to recreate them
161
            $justdir = $rdir->fullpath(false).$values[7];
162
            if (!file_exists($justdir)) {
163
                if (!mkdir($justdir, $permDirs, true)) {
164
                    throw new RuntimeException('Unable to create directories!');
165
                }
166
            }
167
168
            $source = $values[0];
169
            if (is_dir($source)) {
170
                continue;
171
            }
172
173
            if (!copy($source, $rtp)) {
174
                throw new RuntimeException('Unable to copy files!');
175
            }
176
            $resource = new CcResources($rdir->rootdir(),
177
                                        $values[7].$clean_filename,
178
                                        $rdir->dirname(false));
179
180
            $res = $manifest->addResource($resource, null, CcVersion13::WEBCONTENT);
181
182
            PkgStaticResources::instance()->add($virtual,
183
                                                  $res[0],
184
                                                  $rdir->dirname(false).$values[7].$clean_filename,
185
                                                  $values[1],
186
                                                  $resource);
187
        }
188
189
        PkgStaticResources::instance()->finished = true;
190
    }
191
192
    /**
193
     * Excerpt from IMS CC 1.1 overview :
194
     * No spaces in filenames, directory and file references should
195
     * employ all lowercase or all uppercase - no mixed case.
196
     *
197
     * @param string $packageroot
198
     * @param int    $contextid
199
     * @param string $outdir
200
     * @param bool   $allinone
201
     *
202
     * @throws RuntimeException
203
     */
204
    public static function handleStaticContent(CcIManifest &$manifest, $packageroot, $contextid, $outdir, $allinone = true, $folder = null)
205
    {
206
        self::addFiles($manifest, $packageroot, $outdir, $allinone, $folder);
207
208
        return PkgStaticResources::instance()->getValues();
209
    }
210
211
    public static function handleResourceContent(CcIManifest &$manifest, $packageroot, $contextid, $outdir, $allinone = true, $docfilepath = null)
212
    {
213
        $result = [];
214
215
        self::addFiles($manifest, $packageroot, $outdir, $allinone, null, $docfilepath);
216
217
        $files = self::embeddedMapping($packageroot, $contextid, null, $docfilepath);
218
        $rootnode = null;
219
        $rootvals = null;
220
        $depfiles = [];
221
        $depres = [];
222
        $flocation = null;
223
        foreach ($files as $virtual => $values) {
224
            $vals = PkgStaticResources::instance()->getIdentifier($virtual);
225
            $resource = $vals[3];
226
            $identifier = $resource->identifier;
227
            $flocation = $vals[1];
228
            if ($values[1]) {
229
                $rootnode = $resource;
230
                $rootvals = $flocation;
231
                continue;
232
            }
233
            $depres[] = $identifier;
234
            $depfiles[] = $vals[1];
235
            $result[$virtual] = [$identifier, $flocation, false];
236
        }
237
238
        if (!empty($rootnode)) {
239
            $rootnode->files = array_merge($rootnode->files, $depfiles);
240
            $result[$virtual] = [$rootnode->identifier, $rootvals, true];
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $virtual seems to be defined by a foreach iteration on line 223. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
241
        }
242
243
        return $result;
244
    }
245
246
    public static function processLinkedFiles($content, CcIManifest &$manifest, $packageroot,
247
                                                $contextid, $outdir, $webcontent = false)
248
    {
249
        // Detect all embedded files
250
        // copy all files in the cc package stripping any spaces and using only lowercase letters
251
        // add those files as resources of the type webcontent to the manifest
252
        // replace the links to the resource using $IMS-CC-FILEBASE$ and their new locations
253
        // cc_resource has array of files and array of dependencies
254
        // most likely we would need to add all files as independent resources and than
255
        // attach them all as dependencies to the forum tag.
256
        $lfiles = self::embeddedFiles($content);
257
        $text = $content;
258
        $deps = [];
259
        if (!empty($lfiles)) {
260
            $files = self::handleStaticContent($manifest,
261
                                                 $packageroot,
262
                                                 $contextid,
263
                                                 $outdir);
264
            $replaceprefix = $webcontent ? '' : '$IMS-CC-FILEBASE$';
265
            foreach ($lfiles as $lfile) {
266
                if (isset($files[$lfile])) {
267
                    $filename = str_replace('%2F', '/', rawurlencode($lfile));
268
                    $content = str_replace('@@PLUGINFILE@@'.$filename,
269
                                           $replaceprefix.'../'.$files[$lfile][1],
270
                                           $content);
271
                    // For the legacy stuff.
272
                    $content = str_replace('$@FILEPHP@$'.str_replace('/', '$@SLASH@$', $filename),
273
                                           $replaceprefix.'../'.$files[$lfile][1],
274
                                           $content);
275
                    $deps[] = $files[$lfile][0];
276
                }
277
            }
278
            $text = $content;
279
        }
280
281
        return [$text, $deps];
282
    }
283
}
284