/** * Creates a file artefact based on the given entry. * * @param SimpleXMLElement $entry The entry to base the file's data on * @param PluginImport $importer The importer * @param int $parent The ID of the parent artefact for this file * @throws ImportException If the given entry is not detected as being a file * @return ArtefactTypeFile The file artefact created */ public static function create_file(SimpleXMLElement $entry, PluginImport $importer, $parent = null) { if (!self::is_file($entry, $importer)) { throw new ImportException($importer, "create_file(): Cannot create a file artefact from an entry we don't recognise as a file"); } // TODO: make sure there's no arbitrary file inclusion // TODO: the src attribute must be an IRI, according to the ATOM spec. // This means that it could have UTF8 characters in it, and the PHP // documentation doesn't sound hopeful that urldecode will work with // UTF8 characters $pathname = urldecode((string) $entry->content['src']); // TODO: might want to make it easier to get at the directory where the import files are $data = $importer->get('data'); $dir = dirname($data['filename']); // Note: this data is passed (eventually) to ArtefactType->__construct, // which calls strtotime on the dates for us $data = (object) array('title' => (string) $entry->title, 'owner' => $importer->get('usr'), 'filetype' => (string) $entry->content['type']); if (isset($entry->summary)) { $data->description = (string) $entry->summary; } if ($published = strtotime((string) $entry->published)) { $data->ctime = (string) $entry->published; } if ($updated = strtotime((string) $entry->updated)) { $data->mtime = (string) $entry->updated; } if ($parent) { $data->parent = $parent; } $pathname = $dir . DIRECTORY_SEPARATOR . $pathname; // This API sucks, but that's not my problem if (!($id = ArtefactTypeFile::save_file($pathname, $data, $importer->get('usrobj')))) { throw new ImportException($importer, 'TODO: get_string: was unable to import file'); } // Work out if the file was really a profile icon $isprofileicon = false; $match = $entry->xpath('mahara:artefactplugin[@mahara:plugin="file" and @mahara:type="profileicon"]'); if (count($match) == 1) { $isprofileicon = true; } $artefact = artefact_instance_from_id($id); // Work around that save_file doesn't let us set the mtime $artefact->set('mtime', strtotime((string) $entry->updated)); if ($isprofileicon) { $artefact->set('artefacttype', 'profileicon'); $artefact->set('parent', null); // Sadly the process for creating a profile icon is a bit dumb. To // be honest, it shouldn't even be a separate artefact type $basedir = get_config('dataroot') . 'artefact/file/'; $olddir = 'originals/' . $id % 256 . '/'; $newdir = 'profileicons/originals/' . $id % 256 . '/'; check_dir_exists($basedir . $newdir); if (!rename($basedir . $olddir . $id, $basedir . $newdir . $id)) { throw new ImportException($importer, 'TODO: get_string: was unable to move profile icon'); } // Unconditionally set as default, even if there is more than one $importer->get('usrobj')->profileicon = $id; $importer->get('usrobj')->commit(); } $artefact->commit(); return $artefact; }
/** * Attaches a file to a blogpost entry that was just linked directly, rather than having a Leap2a entry * See http://wiki.leapspecs.org/2A/files * * @param SimpleXMLElement $entry * @param SimpleXMLElement $link */ private function create_linked_file(SimpleXMLElement $entry, SimpleXMLElement $link) { $this->trace($link); $pathname = urldecode((string) $link['href']); $dir = dirname($this->get('filename')); $pathname = $dir . '/' . $pathname; if (!file_exists($pathname)) { return false; } // Note: this data is passed (eventually) to ArtefactType->__construct, // which calls strtotime on the dates for us require_once 'file.php'; $data = (object) array('title' => (string) $entry->title . ' ' . get_string('attachment'), 'owner' => $this->get('usr')); $data->oldextension = end(explode('.', $data->title)); return ArtefactTypeFile::save_file($pathname, $data, $this->get('usrobj'), true); }
public function extract($progresscallback = null) { global $USER; $quotauser = $this->owner ? $USER : null; $this->data['basefolderid'] = $this->create_base_folder(); $this->data['folderids'] = array('.' => $this->data['basefolderid']); $this->data['folderscreated'] = 1; $this->data['filescreated'] = 0; $this->data['template'] = (object) array('owner' => $this->get('owner'), 'group' => $this->get('group'), 'institution' => $this->get('institution')); $tempdir = get_config('dataroot') . 'artefact/file/temp'; check_dir_exists($tempdir); if ($this->archivetype == 'tar') { $this->read_archive(); // Untar everything into a temp directory first $tempsubdir = tempnam($tempdir, ''); unlink($tempsubdir); mkdir($tempsubdir, get_config('directorypermissions')); if (!$this->handle->extract($tempsubdir)) { throw new SystemException("Unable to extract archive into {$tempsubdir}"); } $i = 0; foreach ($this->info->names as $name) { $folder = dirname($name); $this->data['template']->parent = $this->data['folderids'][$folder]; $this->data['template']->title = basename($name); // set the file extension for later use (eg by flowplayer) $this->data['template']->extension = pathinfo($this->data['template']->title, PATHINFO_EXTENSION); $this->data['template']->oldextension = $this->data['template']->extension; if (substr($name, -1) == '/') { $this->create_folder($folder); } else { ArtefactTypeFile::save_file($tempsubdir . '/' . $name, $this->data['template'], $quotauser, true); $this->data['filescreated']++; } if ($progresscallback && ++$i % 5 == 0) { call_user_func($progresscallback, $i); } } } else { if ($this->archivetype == 'zip') { $this->open_archive(); $tempfile = tempnam($tempdir, ''); $i = 0; while ($entry = zip_read($this->handle)) { $name = zip_entry_name($entry); $folder = dirname($name); // Create parent folders if necessary if (!isset($this->data['folderids'][$folder])) { $parent = '.'; $child = ''; $path = explode('/', $folder); for ($i = 0; $i < count($path); $i++) { $child .= $path[$i] . '/'; if (!isset($this->data['folderids'][$child])) { $this->data['template']->parent = $this->data['folderids'][$parent]; $this->data['template']->title = $path[$i]; $this->create_folder($parent); } $parent = $child; } } $this->data['template']->parent = $this->data['folderids'][$folder == '.' ? '.' : $folder . '/']; $this->data['template']->title = basename($name); // set the file extension for later use (eg by flowplayer) $this->data['template']->extension = pathinfo($this->data['template']->title, PATHINFO_EXTENSION); $this->data['template']->oldextension = $this->data['template']->extension; if (substr($name, -1) != '/') { $h = fopen($tempfile, 'w'); $size = zip_entry_filesize($entry); $contents = zip_entry_read($entry, $size); fwrite($h, $contents); fclose($h); ArtefactTypeFile::save_file($tempfile, $this->data['template'], $quotauser, true); $this->data['filescreated']++; } if ($progresscallback && ++$i % 5 == 0) { call_user_func($progresscallback, $i); } } } } return $this->data; }
oAAAAAAAAAD4DR1+AAGgmQaxAAAAAElFTkSuQmCC'), 'text/html' => 'te<b>xt/h</b>tml', 'text/plain' => 'text/plain', 'video/x-flv' => file_get_contents(get_config('docroot') . 'junk.flv'), 'application/octet-stream' => '??'); $profileicons = get_records_sql_array("\n SELECT f.*, a.artefacttype\n FROM {artefact_file_files} f JOIN {artefact} a ON f.artefact = a.id\n WHERE a.artefacttype = 'profileicon'", null); db_begin(); foreach ($profileicons as $r) { $filetype = isset($samples[$r->filetype]) ? $r->filetype : 'application/octet-stream'; $dir = get_config('dataroot') . 'artefact/file/profileicons/originals/' . $r->artefact % 256; check_dir_exists($dir); $file = $dir . '/' . $r->artefact; if (!file_exists($file)) { file_put_contents($dir . '/' . $r->artefact, $samples[$filetype]); execute_sql("UPDATE {artefact_file_files} SET size = ?, fileid = ?, filetype = ? WHERE artefact = ?", array(filesize($dir . '/' . $r->artefact), $r->artefact, $filetype, $r->artefact)); } } safe_require('artefact', 'file'); $files = array(); $ids = array(); foreach ($samples as $k => $v) { $n = 'a.' . get_random_key(); $fn = "/tmp/{$n}"; file_put_contents($fn, $v); $d = (object) array('title' => $n, 'owner' => $USER->get('id'), 'filetype' => $k); $id = ArtefactTypeFile::save_file($fn, $d, $USER, true); $ids[$id] = $id; $files[$k] = artefact_instance_from_id($id); } $records = get_records_sql_array("\n SELECT f.*, a.artefacttype\n FROM {artefact_file_files} f JOIN {artefact} a ON f.artefact = a.id\n WHERE a.artefacttype != 'profileicon' AND NOT a.id IN (" . join(',', $ids) . ')', null); foreach ($samples as $k => $v) { execute_sql("\n UPDATE {artefact_file_files} SET size = ?, fileid = ? WHERE filetype = ?", array($files[$k]->get('size'), $files[$k]->get('fileid'), $k)); } db_commit(); set_config('samplefiles', 1);
public function add_artefacts() { // we're just adding them as files into an 'incoming' directory in the user's file area. safe_require('artefact', 'file'); try { $this->importdir = ArtefactTypeFolder::get_folder_id('incoming', get_string('incomingfolderdesc'), null, true, $this->get('usr')); } catch (Exception $e) { throw new ImportException($e->getMessage()); } $savedfiles = array(); // to put files into so we can delete them should we encounter an exception foreach ($this->files as $f) { try { $data = (object) array('title' => $f->wantsfilename, 'description' => $f->wantsfilename . ' (' . get_string('importedfrom', 'mahara', $this->get('importertransport')->get_description()) . ')', 'parent' => $this->importdir, 'owner' => $this->get('usr'), 'container' => 0, 'locked' => 0); if ($imagesize = getimagesize($this->tempdir . 'extract/' . $f->actualfilename)) { $mime = $imagesize['mime']; $data->filetype = $mime; } $id = ArtefactTypeFile::save_file($this->tempdir . 'extract/' . $f->actualfilename, $data, $this->get('usrobj'), true); if (empty($id)) { throw new ImportException("Failed to create new artefact for {$f->sha1}"); } $savedfiles[] = $id; } catch (Exception $e) { foreach ($savedfiles as $fileid) { $tmp = artefact_instance_from_id($fileid); $tmp->delete(); } throw new ImportException('Failed to create some new artefacts'); } } $this->artefacts = $savedfiles; }
/** * Creates a file artefact based on the given entry. * * @param SimpleXMLElement $entry The entry to base the file's data on * @param PluginImportLeap $importer The importer * @param int $parent The ID of the parent artefact for this file * @throws ImportException If the given entry is not detected as being a file * @return ArtefactTypeFile The file artefact created */ public static function create_file(SimpleXMLElement $entry, PluginImportLeap $importer, $parent = null) { if (!self::is_file($entry, $importer)) { throw new ImportException($importer, "create_file(): Cannot create a file artefact from an entry we don't recognise as a file"); } // TODO: make sure there's no arbitrary file inclusion // TODO: the src attribute must be an IRI, according to the ATOM spec. // This means that it could have UTF8 characters in it, and the PHP // documentation doesn't sound hopeful that urldecode will work with // UTF8 characters $pathname = false; $description = ''; if (isset($entry->content['src'])) { $pathname = urldecode((string) $entry->content['src']); $filetype = (string) $entry->content['type']; } else { foreach ($entry->link as $link) { if ($importer->curie_equals($link['rel'], '', 'enclosure') && isset($link['href']) && !$importer->entry_exists((string) $link['href'])) { $pathname = urldecode((string) $link['href']); $filetype = (string) $link['type']; $description = strip_tags(PluginImportLeap::get_entry_content($entry, $importer)); // TODO do we have a better way of stripping tags? and why isn't this html anyway? } } } if (!$pathname) { $importer->trace("WARNING: couldn't find a file for {$entry->id} "); return; } // TODO: might want to make it easier to get at the directory where the import files are $dir = dirname($importer->get('filename')); // Note: this data is passed (eventually) to ArtefactType->__construct, // which calls strtotime on the dates for us $data = (object) array('title' => (string) $entry->title, 'description' => $description, 'owner' => $importer->get('usr'), 'filetype' => $filetype); if (isset($entry->summary) && empty($description)) { $data->description = (string) $entry->summary; } if ($published = strtotime((string) $entry->published)) { $data->ctime = (string) $entry->published; } if ($updated = strtotime((string) $entry->updated)) { $data->mtime = (string) $entry->updated; } if ($parent) { $data->parent = $parent; } $pathname = $dir . DIRECTORY_SEPARATOR . $pathname; // This API sucks, but that's not my problem if (!($id = ArtefactTypeFile::save_file($pathname, $data, $importer->get('usrobj'), true))) { $importer->trace("WARNING: the file for entry {$entry->id} does not exist in the import (path={$pathname})"); return; } $artefact = artefact_instance_from_id($id); $artefact->set('tags', PluginImportLeap::get_entry_tags($entry)); // Work out if the file was really a profile icon $isprofileicon = false; if ($artefact->get('artefacttype') == 'image') { $match = $entry->xpath('mahara:artefactplugin[@mahara:plugin="file" and @mahara:type="profileicon"]'); if (count($match) == 1) { $isprofileicon = true; } else { if ($importer->get('persondataid')) { $persondata = $importer->get_entry_by_id($importer->get('persondataid')); if (count($persondata->xpath('a:link[@rel="related" and @href="' . (string) $entry->id . '"]')) == 1) { $isprofileicon = true; } } } } // Work around that save_file doesn't let us set the mtime $artefact->set('mtime', strtotime((string) $entry->updated)); if ($isprofileicon) { $artefact->set('artefacttype', 'profileicon'); $artefact->set('parent', null); // Sadly the process for creating a profile icon is a bit dumb. To // be honest, it shouldn't even be a separate artefact type $basedir = get_config('dataroot') . 'artefact/file/'; $olddir = 'originals/' . $id % 256 . '/'; $newdir = 'profileicons/originals/' . $id % 256 . '/'; check_dir_exists($basedir . $newdir); if (!rename($basedir . $olddir . $id, $basedir . $newdir . $id)) { throw new ImportException($importer, 'TODO: get_string: was unable to move profile icon'); } } $artefact->commit(); return $artefact; }
/** * Logic shared by create_file_from_request() and create_file(). This actually takes the data and processes it into a file artefact * @param object $data * @param PluginImportLeap $importer * @param int $parent * @param SimplexMLElement $entry * @param unknown_type $entry_request * @return PluginArtefactFile * @throws ImportException */ private static function create_file_from_entry_data($data, PluginImportLeap $importer, $entryid, $fromrequest = false) { global $USER; if ($fromrequest) { $usr = $USER; } else { $usr = $importer->get('usrobj'); } $data->oldextension = end(explode('.', $data->title)); // This API sucks, but that's not my problem if (!($id = ArtefactTypeFile::save_file($data->pathname, $data, $usr, true))) { $importer->trace("WARNING: the file for entry {$entryid} does not exist in the import (path={$data->pathname})"); return false; } $artefact = artefact_instance_from_id($id); $artefact->set('tags', $data->tags); if ($fromrequest) { $artefact->set('mtime', $data->mtime); } else { // Work around that save_file doesn't let us set the mtime $artefact->set('mtime', strtotime($data->mtime)); } // Now that we've actually imported the file, let's check to see whether it was an image, before making it a real profile icon $isprofileicon = $data->isprofileicon && $artefact->get('artefacttype') == 'image'; if ($isprofileicon) { $artefact->set('artefacttype', 'profileicon'); // Put profile pic in 'profile pics' folder $artefact->set('parent', ArtefactTypeFolder::get_folder_id(get_string('imagesdir', 'artefact.file'), get_string('imagesdirdesc', 'artefact.file'), null, true, $importer->get('usr'))); // Sadly the process for creating a profile icon is a bit dumb. To // be honest, it shouldn't even be a separate artefact type $basedir = get_config('dataroot') . 'artefact/file/'; $olddir = 'originals/' . $id % 256 . '/'; $newdir = 'profileicons/originals/' . $id % 256 . '/'; check_dir_exists($basedir . $newdir); if (!rename($basedir . $olddir . $id, $basedir . $newdir . $id)) { throw new ImportException($importer, 'TODO: get_string: was unable to move profile icon'); } } $artefact->commit(); return $artefact; }
/** * Attaches a file to a blogpost entry that was just linked directly, rather than having a Leap2a entry * See http://wiki.leapspecs.org/2A/files * * @param SimpleXMLElement $blogpostentry * @param SimpleXMLElement $blogpostlink * @param PluginImportLeap $importer */ private static function attach_linked_file($blogpostentry, $blogpostlink, PluginImportLeap $importer) { $importer->trace($blogpostlink); $pathname = urldecode((string) $blogpostlink['href']); $dir = dirname($importer->get('filename')); $pathname = $dir . '/' . $pathname; if (!file_exists($pathname)) { return false; } // Note: this data is passed (eventually) to ArtefactType->__construct, // which calls strtotime on the dates for us require_once 'file.php'; $data = (object) array('title' => (string) $blogpostentry->title . ' ' . get_string('attachment', 'artefact.blog'), 'owner' => $importer->get('usr')); $data->oldextension = end(explode('.', $data->title)); return ArtefactTypeFile::save_file($pathname, $data, $importer->get('usrobj'), true); }