function copy_folder_to_cloudfiles($channel, $observer_hash, $srcpath, $cloudpath) { if (!is_dir($srcpath) || !is_readable($srcpath)) { logger('Error reading source path: ' . $srcpath, LOGGER_NORMAL); return false; } $nodes = array_diff(scandir($srcpath), array('.', '..')); foreach ($nodes as $node) { $clouddir = $cloudpath . '/' . $node; // Sub-folder in cloud files destination $nodepath = $srcpath . '/' . $node; // Sub-folder in source path if (is_dir($nodepath)) { $x = attach_mkdirp($channel, $observer_hash, array('pathname' => $clouddir)); if (!$x['success']) { logger('Error creating cloud path: ' . $clouddir, LOGGER_NORMAL); return false; } // Recursively call this function where the source and destination are the subfolders $success = copy_folder_to_cloudfiles($channel, $observer_hash, $nodepath, $clouddir); if (!$success) { logger('Error copying contents of folder: ' . $nodepath, LOGGER_NORMAL); return false; } } elseif (is_file($nodepath) && is_readable($nodepath)) { $x = attach_store($channel, $observer_hash, 'import', array('directory' => $cloudpath, 'src' => $nodepath, 'filename' => $node, 'filesize' => @filesize($nodepath), 'preserve_original' => true)); if (!$x['success']) { logger('Error copying file: ' . $nodepath, LOGGER_NORMAL); logger('Return value: ' . json_encode($x), LOGGER_NORMAL); return false; } } else { logger('Error scanning source path', LOGGER_NORMAL); return false; } } return true; }
/** * A lot going on in this function, and some of it is old cruft and some is new cruft * and the entire thing probably needs to be refactored. It started out just storing * files, before we had DAV. It was made extensible to do extra stuff like edit an * existing file or optionally store a separate revision using $options to choose between different * storage models. Along the way we moved from * DB data storage to file system storage. * Then DAV came along and used different upload methods depending on whether the * file was stored as a DAV directory object or updated as a file object. One of these * is essentially an update and the other is basically an upload, but doesn't use the traditional PHP * upload workflow. * Then came hubzilla and we tried to merge photo functionality with the file storage. Most of * that integration occurs within this function. * This required overlap with the old photo_upload stuff and photo albums were * completely different concepts from directories which needed to be reconciled somehow. * The old revision stuff is kind of orphaned currently. There's new revision stuff for photos * which attaches (2) etc. onto the name, but doesn't integrate with the attach table revisioning. * That's where it sits currently. I repeat it needs to be refactored, and this note is here * for future explorers and those who may be doing that work to understand where it came * from and got to be the monstrosity of tangled unrelated code that it currently is. */ function attach_store($channel, $observer_hash, $options = '', $arr = null) { require_once 'include/photos.php'; call_hooks('photo_upload_begin', $arr); $ret = array('success' => false); $channel_id = $channel['channel_id']; $sql_options = ''; $source = $arr ? $arr['source'] : ''; $album = $arr ? $arr['album'] : ''; $newalbum = $arr ? $arr['newalbum'] : ''; $hash = $arr && $arr['hash'] ? $arr['hash'] : null; $upload_path = $arr && $arr['directory'] ? $arr['directory'] : ''; $visible = $arr && $arr['visible'] ? $arr['visible'] : ''; $observer = array(); if ($observer_hash) { $x = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($observer_hash)); if ($x) { $observer = $x[0]; } } logger('arr: ' . print_r($arr, true)); if (!perm_is_allowed($channel_id, $observer_hash, 'write_storage')) { $ret['message'] = t('Permission denied.'); return $ret; } $str_group_allow = perms2str($arr['group_allow']); $str_contact_allow = perms2str($arr['contact_allow']); $str_group_deny = perms2str($arr['group_deny']); $str_contact_deny = perms2str($arr['contact_deny']); // The 'update' option sets db values without uploading a new attachment // 'replace' replaces the existing uploaded data // 'revision' creates a new revision with new upload data // Default is to upload a new file // revise or update must provide $arr['hash'] of the thing to revise/update // By default remove $src when finished $remove_when_processed = true; if ($options === 'import') { $src = $arr['src']; $filename = $arr['filename']; $filesize = @filesize($src); $hash = $arr['resource_id']; if (array_key_exists('hash', $arr)) { $hash = $arr['hash']; } if (array_key_exists('type', $arr)) { $type = $arr['type']; } if ($arr['preserve_original']) { $remove_when_processed = false; } // if importing a directory, just do it now and go home - we're done. if (array_key_exists('is_dir', $arr) && intval($arr['is_dir'])) { $x = attach_mkdir($channel, $observer_hash, $arr); if ($x['message']) { logger('import_directory: ' . $x['message']); } return; } } elseif ($options !== 'update') { $f = array('src' => '', 'filename' => '', 'filesize' => 0, 'type' => ''); call_hooks('photo_upload_file', $f); call_hooks('attach_upload_file', $f); if (x($f, 'src') && x($f, 'filesize')) { $src = $f['src']; $filename = $f['filename']; $filesize = $f['filesize']; $type = $f['type']; } else { if (!x($_FILES, 'userfile')) { $ret['message'] = t('No source file.'); return $ret; } $src = $_FILES['userfile']['tmp_name']; $filename = basename($_FILES['userfile']['name']); $filesize = intval($_FILES['userfile']['size']); } } $existing_size = 0; if ($options === 'replace') { $x = q("select id, hash, filesize from attach where id = %d and uid = %d limit 1", intval($arr['id']), intval($channel_id)); if (!$x) { $ret['message'] = t('Cannot locate file to replace'); return $ret; } $existing_id = $x[0]['id']; $existing_size = intval($x[0]['filesize']); $hash = $x[0]['hash']; } if ($options === 'revise' || $options === 'update') { $sql_options = " order by revision desc "; if ($options === 'update' && $arr && array_key_exists('revision', $arr)) { $sql_options = " and revision = " . intval($arr['revision']) . " "; } $x = q("select id, aid, uid, filename, filetype, filesize, hash, revision, folder, os_storage, is_photo, flags, created, edited, allow_cid, allow_gid, deny_cid, deny_gid from attach where hash = '%s' and uid = %d {$sql_options} limit 1", dbesc($arr['hash']), intval($channel_id)); if (!$x) { $ret['message'] = t('Cannot locate file to revise/update'); return $ret; } $hash = $x[0]['hash']; } $def_extension = ''; $is_photo = 0; $gis = @getimagesize($src); logger('getimagesize: ' . print_r($gis, true), LOGGER_DATA); if ($gis && ($gis[2] === IMAGETYPE_GIF || $gis[2] === IMAGETYPE_JPEG || $gis[2] === IMAGETYPE_PNG)) { $is_photo = 1; if ($gis[2] === IMAGETYPE_GIF) { $def_extension = '.gif'; } if ($gis[2] === IMAGETYPE_JPEG) { $def_extension = '.jpg'; } if ($gis[2] === IMAGETYPE_PNG) { $def_extension = '.png'; } } $pathname = ''; if ($is_photo) { if ($newalbum) { $pathname = filepath_macro($newalbum); } elseif (array_key_exists('folder', $arr)) { $x = q("select filename from attach where hash = '%s' and uid = %d limit 1", dbesc($arr['folder']), intval($channel['channel_id'])); if ($x) { $pathname = $x[0]['filename']; } } else { $pathname = filepath_macro($album); } } else { $pathname = filepath_macro($upload_path); } $darr = array('pathname' => $pathname); // if we need to create a directory, use the channel default permissions. $darr['allow_cid'] = $channel['allow_cid']; $darr['allow_gid'] = $channel['allow_gid']; $darr['deny_cid'] = $channel['deny_cid']; $darr['deny_gid'] = $channel['deny_gid']; $direct = null; if ($pathname) { $x = attach_mkdirp($channel, $observer_hash, $darr); $folder_hash = $x['success'] ? $x['data']['hash'] : ''; $direct = $x['success'] ? $x['data'] : null; if (!$str_contact_allow && !$str_group_allow && !$str_contact_deny && !$str_group_deny) { $str_contact_allow = $x['data']['allow_cid']; $str_group_allow = $x['data']['allow_gid']; $str_contact_deny = $x['data']['deny_cid']; $str_group_deny = $x['data']['deny_gid']; } } else { $folder_hash = $arr && array_key_exists('folder', $arr) ? $arr['folder'] : ''; } if (!$options || $options === 'import') { // A freshly uploaded file. Check for duplicate and resolve with the channel's overwrite settings. $r = q("select filename, id, hash, filesize from attach where filename = '%s' and folder = '%s' ", dbesc($filename), dbesc($folder_hash)); if ($r) { $overwrite = get_pconfig($channel_id, 'system', 'overwrite_dup_files'); if ($overwrite) { $options = 'replace'; $existing_id = $x[0]['id']; $existing_size = intval($x[0]['filesize']); $hash = $x[0]['hash']; } else { if (strpos($filename, '.') !== false) { $basename = substr($filename, 0, strrpos($filename, '.')); $ext = substr($filename, strrpos($filename, '.')); } else { $basename = $filename; $ext = $def_extension; } $r = q("select filename from attach where ( filename = '%s' OR filename like '%s' ) and folder = '%s' ", dbesc($basename . $ext), dbesc($basename . '(%)' . $ext), dbesc($folder_hash)); if ($r) { $x = 1; do { $found = false; foreach ($r as $rr) { if ($rr['filename'] === $basename . '(' . $x . ')' . $ext) { $found = true; break; } } if ($found) { $x++; } } while ($found); $filename = $basename . '(' . $x . ')' . $ext; } else { $filename = $basename . $ext; } } } } if (!$hash) { $hash = random_string(); } // Check storage limits if ($options !== 'update') { $maxfilesize = get_config('system', 'maxfilesize'); if ($maxfilesize && $filesize > $maxfilesize) { $ret['message'] = sprintf(t('File exceeds size limit of %d'), $maxfilesize); if ($remove_when_processed) { @unlink($src); } call_hooks('photo_upload_end', $ret); return $ret; } $limit = service_class_fetch($channel_id, 'attach_upload_limit'); if ($limit !== false) { $r = q("select sum(filesize) as total from attach where aid = %d ", intval($channel['channel_account_id'])); if ($r && $r[0]['total'] + $filesize > $limit - $existing_size) { $ret['message'] = upgrade_message(true) . sprintf(t("You have reached your limit of %1\$.0f Mbytes attachment storage."), $limit / 1024000); if ($remove_when_processed) { @unlink($src); } call_hooks('photo_upload_end', $ret); return $ret; } } $mimetype = isset($type) && $type ? $type : z_mime_content_type($filename); } $os_basepath = 'store/' . $channel['channel_address'] . '/'; $os_relpath = ''; if ($folder_hash) { $curr = find_folder_hash_by_attach_hash($channel_id, $folder_hash, true); if ($curr) { $os_relpath .= $curr . '/'; } $os_relpath .= $folder_hash . '/'; } $os_relpath .= $hash; if ($src) { @file_put_contents($os_basepath . $os_relpath, @file_get_contents($src)); } if (array_key_exists('created', $arr)) { $created = $arr['created']; } else { $created = datetime_convert(); } if (array_key_exists('edited', $arr)) { $edited = $arr['edited']; } else { $edited = $created; } if ($options === 'replace') { $r = q("update attach set filename = '%s', filetype = '%s', folder = '%s', filesize = %d, os_storage = %d, is_photo = %d, data = '%s', edited = '%s' where id = %d and uid = %d", dbesc($filename), dbesc($mimetype), dbesc($folder_hash), intval($filesize), intval(1), intval($is_photo), dbesc($os_relpath), dbesc($created), intval($existing_id), intval($channel_id)); } elseif ($options === 'revise') { $r = q("insert into attach ( aid, uid, hash, creator, filename, filetype, folder, filesize, revision, os_storage, is_photo, data, created, edited, allow_cid, allow_gid, deny_cid, deny_gid )\n\t\t\tVALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", intval($x[0]['aid']), intval($channel_id), dbesc($x[0]['hash']), dbesc($observer_hash), dbesc($filename), dbesc($mimetype), dbesc($folder_hash), intval($filesize), intval($x[0]['revision'] + 1), intval(1), intval($is_photo), dbesc($os_relpath), dbesc($created), dbesc($created), dbesc($x[0]['allow_cid']), dbesc($x[0]['allow_gid']), dbesc($x[0]['deny_cid']), dbesc($x[0]['deny_gid'])); } elseif ($options === 'update') { $r = q("update attach set filename = '%s', filetype = '%s', folder = '%s', edited = '%s', os_storage = %d, is_photo = %d, \n\t\t\tallow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where id = %d and uid = %d", dbesc(array_key_exists('filename', $arr) ? $arr['filename'] : $x[0]['filename']), dbesc(array_key_exists('filetype', $arr) ? $arr['filetype'] : $x[0]['filetype']), dbesc($folder_hash ? $folder_hash : $x[0]['folder']), dbesc($created), dbesc(array_key_exists('os_storage', $arr) ? $arr['os_storage'] : $x[0]['os_storage']), dbesc(array_key_exists('is_photo', $arr) ? $arr['is_photo'] : $x[0]['is_photo']), dbesc(array_key_exists('allow_cid', $arr) ? $arr['allow_cid'] : $x[0]['allow_cid']), dbesc(array_key_exists('allow_gid', $arr) ? $arr['allow_gid'] : $x[0]['allow_gid']), dbesc(array_key_exists('deny_cid', $arr) ? $arr['deny_cid'] : $x[0]['deny_cid']), dbesc(array_key_exists('deny_gid', $arr) ? $arr['deny_gid'] : $x[0]['deny_gid']), intval($x[0]['id']), intval($x[0]['uid'])); } else { $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, filetype, folder, filesize, revision, os_storage, is_photo, data, created, edited, allow_cid, allow_gid,deny_cid, deny_gid )\n\t\t\tVALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", intval($channel['channel_account_id']), intval($channel_id), dbesc($hash), dbesc(get_observer_hash()), dbesc($filename), dbesc($mimetype), dbesc($folder_hash), intval($filesize), intval(0), intval(1), intval($is_photo), dbesc($os_relpath), dbesc($created), dbesc($created), dbesc($arr && array_key_exists('allow_cid', $arr) ? $arr['allow_cid'] : $str_contact_allow), dbesc($arr && array_key_exists('allow_gid', $arr) ? $arr['allow_gid'] : $str_group_allow), dbesc($arr && array_key_exists('deny_cid', $arr) ? $arr['deny_cid'] : $str_contact_deny), dbesc($arr && array_key_exists('deny_gid', $arr) ? $arr['deny_gid'] : $str_group_deny)); } if ($is_photo) { $args = array('source' => $source, 'visible' => $visible, 'resource_id' => $hash, 'album' => basename($pathname), 'os_path' => $os_basepath . $os_relpath, 'filename' => $filename, 'getimagesize' => $gis, 'directory' => $direct); if ($arr['contact_allow']) { $args['contact_allow'] = $arr['contact_allow']; } if ($arr['group_allow']) { $args['group_allow'] = $arr['group_allow']; } if ($arr['contact_deny']) { $args['contact_deny'] = $arr['contact_deny']; } if ($arr['group_deny']) { $args['group_deny'] = $arr['group_deny']; } if (array_key_exists('allow_cid', $arr)) { $args['allow_cid'] = $arr['allow_cid']; } if (array_key_exists('allow_gid', $arr)) { $args['allow_gid'] = $arr['allow_gid']; } if (array_key_exists('deny_cid', $arr)) { $args['deny_cid'] = $arr['deny_cid']; } if (array_key_exists('deny_gid', $arr)) { $args['deny_gid'] = $arr['deny_gid']; } $args['created'] = $created; $args['edited'] = $edited; if ($arr['item']) { $args['item'] = $arr['item']; } $p = photo_upload($channel, $observer, $args); if ($p['success']) { $ret['body'] = $p['body']; } } if ($options !== 'update' && $remove_when_processed) { @unlink($src); } if (!$r) { $ret['message'] = t('File upload failed. Possible system limit or action terminated.'); call_hooks('photo_upload_end', $ret); return $ret; } // Caution: This re-uses $sql_options set further above $r = q("select id, aid, uid, hash, creator, filename, filetype, filesize, revision, folder, os_storage, is_photo, flags, created, edited, allow_cid, allow_gid, deny_cid, deny_gid from attach where uid = %d and hash = '%s' {$sql_options} limit 1", intval($channel_id), dbesc($hash)); if (!$r) { $ret['message'] = t('Stored file could not be verified. Upload failed.'); call_hooks('photo_upload_end', $ret); return $ret; } $ret['success'] = true; $ret['data'] = $r[0]; if (!$is_photo) { // This would've been called already with a success result in photos_upload() if it was a photo. call_hooks('photo_upload_end', $ret); } return $ret; }
function post() { $action = $_REQUEST['action']; if ($action) { switch ($action) { case 'scan': // the state of this variable tracks whether website files have been scanned (null, true, false) $cloud = null; // Website files are to be imported from an uploaded zip file if ($_FILES && array_key_exists('zip_file', $_FILES) && isset($_POST['w_upload'])) { $source = $_FILES["zip_file"]["tmp_name"]; $type = $_FILES["zip_file"]["type"]; $okay = false; $accepted_types = array('application/zip', 'application/x-zip-compressed', 'multipart/x-zip', 'application/x-compressed'); foreach ($accepted_types as $mime_type) { if ($mime_type == $type) { $okay = true; break; } } if (!$okay) { notice(t('Invalid file type.') . EOL); return; } $zip = new \ZipArchive(); if ($zip->open($source) === true) { $tmp_folder_name = random_string(5); $website = dirname($source) . '/' . $tmp_folder_name; $zip->extractTo($website); // change this to the correct site path $zip->close(); @unlink($source); // delete the compressed file now that the content has been extracted $cloud = false; } else { notice(t('Error opening zip file') . EOL); return null; } } // Website files are to be imported from the channel cloud files if ($_POST && array_key_exists('path', $_POST) && isset($_POST['cloudsubmit'])) { $channel = \App::get_channel(); $dirpath = get_dirpath_by_cloudpath($channel, $_POST['path']); if (!$dirpath) { notice(t('Invalid folder path.') . EOL); return null; } $cloud = true; } // If the website files were uploaded or specified in the cloud files, then $cloud // should be either true or false if ($cloud !== null) { require_once 'include/import.php'; $elements = []; if ($cloud) { $path = $_POST['path']; } else { $path = $website; } $elements['pages'] = scan_webpage_elements($path, 'page', $cloud); $elements['layouts'] = scan_webpage_elements($path, 'layout', $cloud); $elements['blocks'] = scan_webpage_elements($path, 'block', $cloud); $_SESSION['blocks'] = $elements['blocks']; $_SESSION['layouts'] = $elements['layouts']; $_SESSION['pages'] = $elements['pages']; if (!(empty($elements['pages']) && empty($elements['blocks']) && empty($elements['layouts']))) { //info( t('Webpages elements detected.') . EOL); $_SESSION['action'] = 'import'; } else { notice(t('No webpage elements detected.') . EOL); $_SESSION['action'] = null; } } // If the website elements were imported from a zip file, delete the temporary decompressed files if ($cloud === false && $website && $elements) { $_SESSION['tempimportpath'] = $website; //rrmdir($website); // Delete the temporary decompressed files } break; case 'importselected': require_once 'include/import.php'; $channel = \App::get_channel(); // Import layout first so that pages that reference new layouts will find // the mid of layout items in the database // Obtain the user-selected layouts to import and import them $checkedlayouts = $_POST['layout']; $layouts = []; if (!empty($checkedlayouts)) { foreach ($checkedlayouts as $name) { foreach ($_SESSION['layouts'] as &$layout) { if ($layout['name'] === $name) { $layout['import'] = 1; $layoutstoimport[] = $layout; } } } foreach ($layoutstoimport as $elementtoimport) { $layouts[] = import_webpage_element($elementtoimport, $channel, 'layout'); } } $_SESSION['import_layouts'] = $layouts; // Obtain the user-selected blocks to import and import them $checkedblocks = $_POST['block']; $blocks = []; if (!empty($checkedblocks)) { foreach ($checkedblocks as $name) { foreach ($_SESSION['blocks'] as &$block) { if ($block['name'] === $name) { $block['import'] = 1; $blockstoimport[] = $block; } } } foreach ($blockstoimport as $elementtoimport) { $blocks[] = import_webpage_element($elementtoimport, $channel, 'block'); } } $_SESSION['import_blocks'] = $blocks; // Obtain the user-selected pages to import and import them $checkedpages = $_POST['page']; $pages = []; if (!empty($checkedpages)) { foreach ($checkedpages as $pagelink) { foreach ($_SESSION['pages'] as &$page) { if ($page['pagelink'] === $pagelink) { $page['import'] = 1; $pagestoimport[] = $page; } } } foreach ($pagestoimport as $elementtoimport) { $pages[] = import_webpage_element($elementtoimport, $channel, 'page'); } } $_SESSION['import_pages'] = $pages; if (!(empty($_SESSION['import_pages']) && empty($_SESSION['import_blocks']) && empty($_SESSION['import_layouts']))) { info(t('Import complete.') . EOL); } if (isset($_SESSION['tempimportpath'])) { rrmdir($_SESSION['tempimportpath']); // Delete the temporary decompressed files unset($_SESSION['tempimportpath']); } break; case 'exportzipfile': if (isset($_POST['w_download'])) { $_SESSION['action'] = 'export_select_list'; $_SESSION['export'] = 'zipfile'; if (isset($_POST['zipfilename']) && $_POST['zipfilename'] !== '') { $filename = filter_var($_POST['zipfilename'], FILTER_SANITIZE_ENCODED); } else { $filename = 'website.zip'; } $_SESSION['zipfilename'] = $filename; } break; case 'exportcloud': if (isset($_POST['exportcloudpath']) && $_POST['exportcloudpath'] !== '') { $_SESSION['action'] = 'export_select_list'; $_SESSION['export'] = 'cloud'; $_SESSION['exportcloudpath'] = filter_var($_POST['exportcloudpath'], FILTER_SANITIZE_ENCODED); } break; case 'cloud': case 'zipfile': $channel = \App::get_channel(); $tmp_folder_name = random_string(10); $zip_folder_name = random_string(10); $zip_filename = $_SESSION['zipfilename']; $tmp_folderpath = '/tmp/' . $tmp_folder_name; $zip_folderpath = '/tmp/' . $zip_folder_name; if (!mkdir($zip_folderpath, 0770, false)) { logger('Error creating zip file export folder: ' . $zip_folderpath, LOGGER_NORMAL); json_return_and_die(array('message' => 'Error creating zip file export folder')); } $zip_filepath = '/tmp/' . $zip_folder_name . '/' . $zip_filename; $checkedblocks = $_POST['block']; $blocks = []; if (!empty($checkedblocks)) { foreach ($checkedblocks as $mid) { $b = q("select iconfig.v, iconfig.k, mimetype, title, body from iconfig \n\t\t\t\t\t\t\t\t\t\t\t\tleft join item on item.id = iconfig.iid \n\t\t\t\t\t\t\t\t\t\t\t\twhere mid = '%s' and item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'BUILDBLOCK' order by iconfig.v asc limit 1", dbesc($mid), intval($channel['channel_id'])); if ($b) { $b = $b[0]; $blockinfo = array('body' => $b['body'], 'mimetype' => $b['mimetype'], 'title' => $b['title'], 'name' => $b['v'], 'json' => array('title' => $b['title'], 'name' => $b['v'], 'mimetype' => $b['mimetype'])); switch ($blockinfo['mimetype']) { case 'text/html': $block_ext = 'html'; break; case 'text/bbcode': $block_ext = 'bbcode'; break; case 'text/markdown': $block_ext = 'md'; break; case 'application/x-pdl': $block_ext = 'pdl'; break; case 'application/x-php': $block_ext = 'php'; break; default: $block_ext = 'bbcode'; break; } $block_filename = $blockinfo['name'] . '.' . $block_ext; $tmp_blockfolder = $tmp_folderpath . '/blocks/' . $blockinfo['name']; $block_filepath = $tmp_blockfolder . '/' . $block_filename; $blockinfo['json']['contentfile'] = $block_filename; $block_jsonpath = $tmp_blockfolder . '/block.json'; if (!is_dir($tmp_blockfolder) && !mkdir($tmp_blockfolder, 0770, true)) { logger('Error creating temp export folder: ' . $tmp_blockfolder, LOGGER_NORMAL); json_return_and_die(array('message' => 'Error creating temp export folder')); } file_put_contents($block_filepath, $blockinfo['body']); file_put_contents($block_jsonpath, json_encode($blockinfo['json'], JSON_UNESCAPED_SLASHES)); } } } $checkedlayouts = $_POST['layout']; $layouts = []; if (!empty($checkedlayouts)) { foreach ($checkedlayouts as $mid) { $l = q("select iconfig.v, iconfig.k, mimetype, title, body from iconfig \n\t\t\t\t\t\t\t\t\t\t\t\tleft join item on item.id = iconfig.iid \n\t\t\t\t\t\t\t\t\t\t\t\twhere mid = '%s' and item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'PDL' order by iconfig.v asc limit 1", dbesc($mid), intval($channel['channel_id'])); if ($l) { $l = $l[0]; $layoutinfo = array('body' => $l['body'], 'mimetype' => $l['mimetype'], 'description' => $l['title'], 'name' => $l['v'], 'json' => array('description' => $l['title'], 'name' => $l['v'], 'mimetype' => $l['mimetype'])); switch ($layoutinfo['mimetype']) { case 'text/bbcode': default: $layout_ext = 'bbcode'; break; } $layout_filename = $layoutinfo['name'] . '.' . $layout_ext; $tmp_layoutfolder = $tmp_folderpath . '/layouts/' . $layoutinfo['name']; $layout_filepath = $tmp_layoutfolder . '/' . $layout_filename; $layoutinfo['json']['contentfile'] = $layout_filename; $layout_jsonpath = $tmp_layoutfolder . '/layout.json'; if (!is_dir($tmp_layoutfolder) && !mkdir($tmp_layoutfolder, 0770, true)) { logger('Error creating temp export folder: ' . $tmp_layoutfolder, LOGGER_NORMAL); json_return_and_die(array('message' => 'Error creating temp export folder')); } file_put_contents($layout_filepath, $layoutinfo['body']); file_put_contents($layout_jsonpath, json_encode($layoutinfo['json'], JSON_UNESCAPED_SLASHES)); } } } $checkedpages = $_POST['page']; $pages = []; if (!empty($checkedpages)) { foreach ($checkedpages as $mid) { $p = q("select * from iconfig left join item on iconfig.iid = item.id \n\t\t\t\t\t\t\t\t\t\t\t\twhere item.uid = %d and item.mid = '%s' and iconfig.cat = 'system' and iconfig.k = 'WEBPAGE' and item_type = %d", intval($channel['channel_id']), dbesc($mid), intval(ITEM_TYPE_WEBPAGE)); if ($p) { foreach ($p as $pp) { // Get the associated layout $layoutinfo = array(); if ($pp['layout_mid']) { $l = q("select iconfig.v, iconfig.k, mimetype, title, body from iconfig \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tleft join item on item.id = iconfig.iid \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\twhere mid = '%s' and item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'PDL' order by iconfig.v asc limit 1", dbesc($pp['layout_mid']), intval($channel['channel_id'])); if ($l) { $l = $l[0]; $layoutinfo = array('body' => $l['body'], 'mimetype' => $l['mimetype'], 'description' => $l['title'], 'name' => $l['v'], 'json' => array('description' => $l['title'], 'name' => $l['v'])); switch ($layoutinfo['mimetype']) { case 'text/bbcode': default: $layout_ext = 'bbcode'; break; } $layout_filename = $layoutinfo['name'] . '.' . $layout_ext; $tmp_layoutfolder = $tmp_folderpath . '/layouts/' . $layoutinfo['name']; $layout_filepath = $tmp_layoutfolder . '/' . $layout_filename; $layoutinfo['json']['contentfile'] = $layout_filename; $layout_jsonpath = $tmp_layoutfolder . '/layout.json'; if (!is_dir($tmp_layoutfolder) && !mkdir($tmp_layoutfolder, 0770, true)) { logger('Error creating temp export folder: ' . $tmp_layoutfolder, LOGGER_NORMAL); json_return_and_die(array('message' => 'Error creating temp export folder')); } file_put_contents($layout_filepath, $layoutinfo['body']); file_put_contents($layout_jsonpath, json_encode($layoutinfo['json'], JSON_UNESCAPED_SLASHES)); } } switch ($pp['mimetype']) { case 'text/html': $page_ext = 'html'; break; case 'text/bbcode': $page_ext = 'bbcode'; break; case 'text/markdown': $page_ext = 'md'; break; case 'application/x-pdl': $page_ext = 'pdl'; break; case 'application/x-php': $page_ext = 'php'; break; default: break; } $pageinfo = array('title' => $pp['title'], 'body' => $pp['body'], 'pagelink' => $pp['v'], 'mimetype' => $pp['mimetype'], 'contentfile' => $pp['v'] . '.' . $page_ext, 'layout' => x($layoutinfo, 'name') ? $layoutinfo['name'] : '', 'json' => array('title' => $pp['title'], 'pagelink' => $pp['v'], 'mimetype' => $pp['mimetype'], 'layout' => x($layoutinfo, 'name') ? $layoutinfo['name'] : '')); $page_filename = $pageinfo['pagelink'] . '.' . $page_ext; $tmp_pagefolder = $tmp_folderpath . '/pages/' . $pageinfo['pagelink']; $page_filepath = $tmp_pagefolder . '/' . $page_filename; $page_jsonpath = $tmp_pagefolder . '/page.json'; $pageinfo['json']['contentfile'] = $page_filename; if (!is_dir($tmp_pagefolder) && !mkdir($tmp_pagefolder, 0770, true)) { logger('Error creating temp export folder: ' . $tmp_pagefolder, LOGGER_NORMAL); json_return_and_die(array('message' => 'Error creating temp export folder')); } file_put_contents($page_filepath, $pageinfo['body']); file_put_contents($page_jsonpath, json_encode($pageinfo['json'], JSON_UNESCAPED_SLASHES)); } } } } if ($action === 'zipfile') { // Generate the zip file \Zotlabs\Lib\ExtendedZip::zipTree($tmp_folderpath, $zip_filepath, \ZipArchive::CREATE); // Output the file for download header('Content-disposition: attachment; filename="' . $zip_filename . '"'); header("Content-Type: application/zip"); $success = readfile($zip_filepath); } elseif ($action === 'cloud') { // Only zipfile or cloud should be possible values for $action here if (isset($_SESSION['exportcloudpath'])) { require_once 'include/attach.php'; $cloudpath = urldecode($_SESSION['exportcloudpath']); $channel = \App::get_channel(); $dirpath = get_dirpath_by_cloudpath($channel, $cloudpath); if (!$dirpath) { $x = attach_mkdirp($channel, $channel['channel_hash'], array('pathname' => $cloudpath)); $folder_hash = $x['success'] ? $x['data']['hash'] : ''; if (!$x['success']) { logger('Failed to create cloud file folder', LOGGER_NORMAL); } $dirpath = get_dirpath_by_cloudpath($channel, $cloudpath); if (!is_dir($dirpath)) { logger('Failed to create cloud file folder', LOGGER_NORMAL); } } $success = copy_folder_to_cloudfiles($channel, $channel['channel_hash'], $tmp_folderpath, $cloudpath); } } if (!$success) { logger('Error exporting webpage elements', LOGGER_NORMAL); } rrmdir($zip_folderpath); rrmdir($tmp_folderpath); // delete temporary files break; default: break; } } }