Has anyone already migrate a site from Drupal to Yii?
Is there some code in Yii that can implement the Drupal encryption and salt for user password?
I have, but not to YII. Its not a big deal. You can use the same salt and encryption in YII as well (easier since both are PHP based).
Check these two pages:
http://www.yiiframework.com/wiki/425
https://api.drupal.org/api/drupal/includes!password.inc/function/user_hash_password/7
Thanks Amar, I follow your links and
I create the YII functions for migrating from drupal7.
They work for me and I could save 1 working hour to someone (not more I guess)
I put all of them in
class UserIdentity extends CUserIdentity
and use this way in
..
} else if (self::user_check_password($this->password, $users->password) ) {
..
in public function authenticate()
private function user_check_password($password, $registered_password) {
if (substr($registered_password, 0, 2) == 'U$') {
// This may be an updated password from user_update_7000(). Such hashes
// have 'U' added as the first character and need an extra md5().
$stored_hash = substr($registered_password, 1);
$password = md5($password);
}
else {
$stored_hash = $registered_password;
}
$type = substr($stored_hash, 0, 3);
switch ($type) {
case '$S$':
// A normal Drupal 7 password using sha512.
$hash = self::_password_crypt('sha512', $password, $stored_hash);
break;
case '$H$':
// phpBB3 uses "$H$" for the same thing as "$P$".
case '$P$':
// A phpass password generated using md5. This is an
// imported password or from an earlier Drupal version.
$hash = self::_password_crypt('md5', $password, $stored_hash);
break;
default:
return FALSE;
}
return ($hash && $stored_hash == $hash);
}
private function user_hash_password($password) {
return self::_password_crypt('sha512', $password, self::_password_generate_salt(15));
}
private function _password_crypt($algo, $password, $setting) {
// The first 12 characters of an existing hash are its setting string.
$setting = substr($setting, 0, 12);
if ($setting[0] != '$' || $setting[2] != '$') {
return FALSE;
}
$count_log2 = self::_password_get_count_log2($setting);
// Hashes may be imported from elsewhere, so we allow != DRUPAL_HASH_COUNT
if ($count_log2 < 7 || $count_log2 > 30) {
return FALSE;
}
$salt = substr($setting, 4, 8);
// Hashes must have an 8 character salt.
if (strlen($salt) != 8) {
return FALSE;
}
// Convert the base 2 logarithm into an integer.
$count = 1 << $count_log2;
// We rely on the hash() function being available in PHP 5.2+.
$hash = hash($algo, $salt . $password, TRUE);
do {
$hash = hash($algo, $hash . $password, TRUE);
} while (--$count);
$len = strlen($hash);
$output = $setting . self::_password_base64_encode($hash, $len);
// _password_base64_encode() of a 16 byte MD5 will always be 22 characters.
// _password_base64_encode() of a 64 byte sha512 will always be 86 characters.
$expected = 12 + ceil((8 * $len) / 6);
return (strlen($output) == $expected) ? substr($output, 0, 55) : FALSE;
}
private function _password_generate_salt($count_log2) {
$output = '$S$';
// Ensure that $count_log2 is within set bounds.
$count_log2 = self::_password_enforce_log2_boundaries($count_log2);
// We encode the final log2 iteration count in base 64.
$itoa64 = self::_password_itoa64();
$output .= $itoa64[$count_log2];
// 6 bytes is the standard salt for a portable phpass hash.
$output .= self::_password_base64_encode(self::drupal_random_bytes(6), 6);
return $output;
}
private function _password_enforce_log2_boundaries($count_log2) {
if ($count_log2 < 7) {
return 7;
}
elseif ($count_log2 > 30) {
return 30;
}
return (int) $count_log2;
}
private function _password_itoa64() {
return './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
}
private function _password_base64_encode($input, $count) {
$output = '';
$i = 0;
$itoa64 = self::_password_itoa64();
do {
$value = ord($input[$i++]);
$output .= $itoa64[$value & 0x3f];
if ($i < $count) {
$value |= ord($input[$i]) << 8;
}
$output .= $itoa64[($value >> 6) & 0x3f];
if ($i++ >= $count) {
break;
}
if ($i < $count) {
$value |= ord($input[$i]) << 16;
}
$output .= $itoa64[($value >> 12) & 0x3f];
if ($i++ >= $count) {
break;
}
$output .= $itoa64[($value >> 18) & 0x3f];
} while ($i < $count);
return $output;
}
private function drupal_random_bytes($count) {
// $random_state does not use drupal_static as it stores random bytes.
static $random_state, $bytes, $has_openssl;
$missing_bytes = $count - strlen($bytes);
if ($missing_bytes > 0) {
// PHP versions prior 5.3.4 experienced openssl_random_pseudo_bytes()
// locking on Windows and rendered it unusable.
if (!isset($has_openssl)) {
$has_openssl = version_compare(PHP_VERSION, '5.3.4', '>=') && function_exists('openssl_random_pseudo_bytes');
}
// openssl_random_pseudo_bytes() will find entropy in a system-dependent
// way.
if ($has_openssl) {
$bytes .= openssl_random_pseudo_bytes($missing_bytes);
}
// Else, read directly from /dev/urandom, which is available on many *nix
// systems and is considered cryptographically secure.
elseif ($fh = #fopen('/dev/urandom', 'rb')) {
// PHP only performs buffered reads, so in reality it will always read
// at least 4096 bytes. Thus, it costs nothing extra to read and store
// that much so as to speed any additional invocations.
$bytes .= fread($fh, max(4096, $missing_bytes));
fclose($fh);
}
// If we couldn't get enough entropy, this simple hash-based PRNG will
// generate a good set of pseudo-random bytes on any system.
// Note that it may be important that our $random_state is passed
// through hash() prior to being rolled into $output, that the two hash()
// invocations are different, and that the extra input into the first one -
// the microtime() - is prepended rather than appended. This is to avoid
// directly leaking $random_state via the $output stream, which could
// allow for trivial prediction of further "random" numbers.
if (strlen($bytes) < $count) {
// Initialize on the first call. The contents of $_SERVER includes a mix of
// user-specific and system information that varies a little with each page.
if (!isset($random_state)) {
$random_state = print_r($_SERVER, TRUE);
if (function_exists('getmypid')) {
// Further initialize with the somewhat random PHP process ID.
$random_state .= getmypid();
}
$bytes = '';
}
do {
$random_state = hash('sha256', microtime() . mt_rand() . $random_state);
$bytes .= hash('sha256', mt_rand() . $random_state, TRUE);
} while (strlen($bytes) < $count);
}
}
$output = substr($bytes, 0, $count);
$bytes = substr($bytes, $count);
return $output;
}
private function _password_get_count_log2($setting) {
$itoa64 = self::_password_itoa64();
return strpos($itoa64, $setting[3]);
}
Related
Summary
I need to replace the Moodle icons in the Moodle file picker with custom icons. I'm referring to the icons that appear in the File Picker window next to "Content Bank" "Server Files" "Recent Files" and "Private Files". (See screenshot below)
screenshot of file picker with Moodle icons
When I pull the URL for the image I get this file path: website.com/theme/image.php/trema/repository_contentbank/1601324857/icon
I can't seem to figure this file path out in order to replace the Moodle icon image. Does anyone know how to do this?
What I've Tried
I've already replaced all of the png and svg Moodle icon files in the "pix" folders. No dice.
I've sifted through the "repository" folder, the "contentbank" folder and any other subfolder I could find but no luck.
I've also looked at the theme/image.php to look for instances where I can replace the file name but I can't figure it out. I'm posting the code for that file below.
Code
Here's the theme/image.php code...
define('NO_DEBUG_DISPLAY', true);
// we need just the values from config.php and minlib.php
define('ABORT_AFTER_CONFIG', true);
require('../config.php'); // this stops immediately at the beginning of lib/setup.php
if ($slashargument = min_get_slash_argument()) {
$slashargument = ltrim($slashargument, '/');
if (substr_count($slashargument, '/') < 3) {
image_not_found();
}
if (strpos($slashargument, '_s/') === 0) {
// Can't use SVG
$slashargument = substr($slashargument, 3);
$usesvg = false;
} else {
$usesvg = true;
}
// image must be last because it may contain "/"
list($themename, $component, $rev, $image) = explode('/', $slashargument, 4);
$themename = min_clean_param($themename, 'SAFEDIR');
$component = min_clean_param($component, 'SAFEDIR');
$rev = min_clean_param($rev, 'INT');
$image = min_clean_param($image, 'SAFEPATH');
} else {
$themename = min_optional_param('theme', 'standard', 'SAFEDIR');
$component = min_optional_param('component', 'core', 'SAFEDIR');
$rev = min_optional_param('rev', -1, 'INT');
$image = min_optional_param('image', '', 'SAFEPATH');
$usesvg = (bool)min_optional_param('svg', '1', 'INT');
}
if (empty($component) or $component === 'moodle' or $component === 'core') {
$component = 'core';
}
if (empty($image)) {
image_not_found();
}
if (file_exists("$CFG->dirroot/theme/$themename/config.php")) {
// exists
} else if (!empty($CFG->themedir) and file_exists("$CFG->themedir/$themename/config.php")) {
// exists
} else {
image_not_found();
}
$candidatelocation = "$CFG->localcachedir/theme/$rev/$themename/pix/$component";
$etag = sha1("$rev/$themename/$component/$image");
if ($rev > 0) {
if (file_exists("$candidatelocation/$image.error")) {
// This is a major speedup if there are multiple missing images,
// the only problem is that random requests may pollute our cache.
image_not_found();
}
$cacheimage = false;
if ($usesvg && file_exists("$candidatelocation/$image.svg")) {
$cacheimage = "$candidatelocation/$image.svg";
$ext = 'svg';
} else if (file_exists("$candidatelocation/$image.png")) {
$cacheimage = "$candidatelocation/$image.png";
$ext = 'png';
} else if (file_exists("$candidatelocation/$image.gif")) {
$cacheimage = "$candidatelocation/$image.gif";
$ext = 'gif';
} else if (file_exists("$candidatelocation/$image.jpg")) {
$cacheimage = "$candidatelocation/$image.jpg";
$ext = 'jpg';
} else if (file_exists("$candidatelocation/$image.jpeg")) {
$cacheimage = "$candidatelocation/$image.jpeg";
$ext = 'jpeg';
} else if (file_exists("$candidatelocation/$image.ico")) {
$cacheimage = "$candidatelocation/$image.ico";
$ext = 'ico';
}
if ($cacheimage) {
if (!empty($_SERVER['HTTP_IF_NONE_MATCH']) || !empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
// We do not actually need to verify the etag value because our files
// never change in cache because we increment the rev parameter.
// 90 days only - based on Moodle point release cadence being every 3 months.
$lifetime = 60 * 60 * 24 * 90;
$mimetype = get_contenttype_from_ext($ext);
header('HTTP/1.1 304 Not Modified');
header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
header('Cache-Control: public, max-age='.$lifetime.', no-transform');
header('Content-Type: '.$mimetype);
header('Etag: "'.$etag.'"');
die;
}
send_cached_image($cacheimage, $etag);
}
}
//=================================================================================
// ok, now we need to start normal moodle script, we need to load all libs and $DB
define('ABORT_AFTER_CONFIG_CANCEL', true);
define('NO_MOODLE_COOKIES', true); // Session not used here
define('NO_UPGRADE_CHECK', true); // Ignore upgrade check
require("$CFG->dirroot/lib/setup.php");
$theme = theme_config::load($themename);
$themerev = theme_get_revision();
if ($themerev <= 0 or $rev != $themerev) {
// Do not send caching headers if they do not request current revision,
// we do not want to pollute browser caches with outdated images.
$imagefile = $theme->resolve_image_location($image, $component, $usesvg);
if (empty($imagefile) or !is_readable($imagefile)) {
image_not_found();
}
send_uncached_image($imagefile);
}
make_localcache_directory('theme', false);
// At this stage caching is enabled, and either:
// * we have no cached copy of the image in any format (either SVG, or non-SVG); or
// * we have a cached copy of the SVG, but the non-SVG was requested by the browser.
//
// Because of the way in which the cache return code works above:
// * if we are allowed to return SVG, we do not need to cache the non-SVG version; however
// * if the browser has requested the non-SVG version, we *must* cache _both_ the SVG, and the non-SVG versions.
// First get all copies - including, potentially, the SVG version.
$imagefile = $theme->resolve_image_location($image, $component, true);
if (empty($imagefile) || !is_readable($imagefile)) {
// Unable to find a copy of the image file in any format.
// We write a .error file for the image now - this will be used above when searching for cached copies to prevent
// trying to find the image in the future.
if (!file_exists($candidatelocation)) {
#mkdir($candidatelocation, $CFG->directorypermissions, true);
}
// Make note we can not find this file.
$cacheimage = "$candidatelocation/$image.error";
$fp = fopen($cacheimage, 'w');
fclose($fp);
image_not_found();
}
// The image was found, and it is readable.
$pathinfo = pathinfo($imagefile);
// Attempt to cache it if necessary.
// We don't really want to overwrite any existing cache items just for the sake of it.
$cacheimage = "$candidatelocation/$image.{$pathinfo['extension']}";
if (!file_exists($cacheimage)) {
// We don't already hold a cached copy of this image. Cache it now.
$cacheimage = cache_image($image, $imagefile, $candidatelocation);
}
if (!$usesvg && $pathinfo['extension'] === 'svg') {
// The browser has requested that a non-SVG version be returned.
// The version found so far is the SVG version - try and find the non-SVG version.
$imagefile = $theme->resolve_image_location($image, $component, false);
if (empty($imagefile) || !is_readable($imagefile)) {
// A non-SVG file could not be found at all.
// The browser has requested a non-SVG version, so we must return image_not_found().
// We must *not* write an .error file because the SVG is available.
image_not_found();
}
// An non-SVG version of image was found - cache it.
// This will be used below in the image serving code.
$cacheimage = cache_image($image, $imagefile, $candidatelocation);
}
if (connection_aborted()) {
// Request was cancelled - do not send anything.
die;
}
// Make sure nothing failed.
clearstatcache();
if (file_exists($cacheimage)) {
// The cached copy was found, and is accessible. Serve it.
send_cached_image($cacheimage, $etag);
}
send_uncached_image($imagefile);
//=================================================================================
//=== utility functions ==
// we are not using filelib because we need to fine tune all header
// parameters to get the best performance.
function send_cached_image($imagepath, $etag) {
global $CFG;
require("$CFG->dirroot/lib/xsendfilelib.php");
// 90 days only - based on Moodle point release cadence being every 3 months.
$lifetime = 60 * 60 * 24 * 90;
$pathinfo = pathinfo($imagepath);
$imagename = $pathinfo['filename'].'.'.$pathinfo['extension'];
$mimetype = get_contenttype_from_ext($pathinfo['extension']);
header('Etag: "'.$etag.'"');
header('Content-Disposition: inline; filename="'.$imagename.'"');
header('Last-Modified: '. gmdate('D, d M Y H:i:s', filemtime($imagepath)) .' GMT');
header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
header('Pragma: ');
header('Cache-Control: public, max-age='.$lifetime.', no-transform, immutable');
header('Accept-Ranges: none');
header('Content-Type: '.$mimetype);
if (xsendfile($imagepath)) {
die;
}
if ($mimetype === 'image/svg+xml') {
// SVG format is a text file. So we can compress SVG files.
if (!min_enable_zlib_compression()) {
header('Content-Length: '.filesize($imagepath));
}
} else {
// No need to compress other image formats.
header('Content-Length: '.filesize($imagepath));
}
readfile($imagepath);
die;
}
function send_uncached_image($imagepath) {
$pathinfo = pathinfo($imagepath);
$imagename = $pathinfo['filename'].'.'.$pathinfo['extension'];
$mimetype = get_contenttype_from_ext($pathinfo['extension']);
header('Content-Disposition: inline; filename="'.$imagename.'"');
header('Last-Modified: '. gmdate('D, d M Y H:i:s', time()) .' GMT');
header('Expires: '. gmdate('D, d M Y H:i:s', time() + 15) .' GMT');
header('Pragma: ');
header('Accept-Ranges: none');
header('Content-Type: '.$mimetype);
header('Content-Length: '.filesize($imagepath));
readfile($imagepath);
die;
}
function image_not_found() {
header('HTTP/1.0 404 not found');
die('Image was not found, sorry.');
}
function get_contenttype_from_ext($ext) {
switch ($ext) {
case 'svg':
return 'image/svg+xml';
case 'png':
return 'image/png';
case 'gif':
return 'image/gif';
case 'jpg':
case 'jpeg':
return 'image/jpeg';
case 'ico':
return 'image/vnd.microsoft.icon';
}
return 'document/unknown';
}
/**
* Caches a given image file.
*
* #param string $image The name of the image that was requested.
* #param string $imagefile The location of the image file we want to cache.
* #param string $candidatelocation The location to cache it in.
* #return string The path to the cached image.
*/
function cache_image($image, $imagefile, $candidatelocation) {
global $CFG;
$pathinfo = pathinfo($imagefile);
$cacheimage = "$candidatelocation/$image.".$pathinfo['extension'];
clearstatcache();
if (!file_exists(dirname($cacheimage))) {
#mkdir(dirname($cacheimage), $CFG->directorypermissions, true);
}
// Prevent serving of incomplete file from concurrent request,
// the rename() should be more atomic than copy().
ignore_user_abort(true);
if (#copy($imagefile, $cacheimage.'.tmp')) {
rename($cacheimage.'.tmp', $cacheimage);
#chmod($cacheimage, $CFG->filepermissions);
#unlink($cacheimage.'.tmp'); // just in case anything fails
}
return $cacheimage;
}
Maybe try enable "Theme designer mode" HOME -> SITE ADMINISTRATION -> APPEARANCE -> THEMES -> THEME SETTINGS and purge caches.
My file is excel .xlsx contains more than 20,000 rows, im using Centos 7 with Nginx web server. When i upload a small size file with few rows it works but when i introduce ShouldQueue and WithChunkReading interfaces it fails even if the file is small. Please I need help. Thanks for your time
Here is the error in a log file
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php
[2019-07-11 14:48:47] development.ERROR: [0] File "/tmp/laravel-excel-4noteGu1gFjJoFClKJQsLw8SgDShm1nd.xlsx" does not exist. on line 344 of file vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php
[2019-07-11 14:48:47] development.ERROR: [0] File "/tmp/laravel-excel-4noteGu1gFjJoFClKJQsLw8SgDShm1nd.xlsx" does not exist. on line 344 of file vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php
Here is a queue error
[2019-07-12 10:11:47][532] Processing: Maatwebsite\Excel\Jobs\QueueImport
[2019-07-12 10:11:47][532] Processed: Maatwebsite\Excel\Jobs\QueueImport
[2019-07-12 10:11:47][533] Processing: Maatwebsite\Excel\Jobs\ReadChunk
[2019-07-12 10:11:47][534] Processing: Maatwebsite\Excel\Jobs\ReadChunk
[2019-07-12 10:11:47][535] Processing: Maatwebsite\Excel\Jobs\ReadChunk
[2019-07-12 10:11:47][535] Failed: Maatwebsite\Excel\Jobs\ReadChunk
Here is my controller function
public function store(Request $request)
{
Excel::import(new HsCodeImport(),"650.xlsx",'local');
return redirect()->back()->withFlashSuccess(__('label.app_success'));
}
Here is my Import file on App\Imports\HsCodeImport.php
<?php
namespace App\Imports;
use App\Exceptions\GeneralException;
use App\Models\Application\Hscode;
use App\Models\ReceiptCode\ReceiptCode;
use Carbon\Carbon;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithBatchInserts;
use Maatwebsite\Excel\Concerns\WithChunkReading;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
class HsCodeImport implements ToCollection, WithHeadingRow, ShouldQueue, WithChunkReading
{
use Importable;
protected $receiptCode;
protected $chunk = 500;
protected $hscode_key = 'hscode';
protected $description_key = 'description';
protected $regulatory_status_key = 'regulatory_status';
protected $comment_key = 'comment';
protected $headings = ['hscode','description','regulatory_status','comment'];
public function __construct(/*ReceiptCode $receiptCode*/)
{
// $this->receiptCode = $receiptCode;
}
/**
* #param Collection $collection
* #throws GeneralException
*/
public function collection(Collection $collection)
{
/*fetching the first Collection*/
$columns = $collection->first();
if (!$columns->has($this->headings)) {
/*When file has different headings*/
} else {
/*When the file has expected headings*/
/*Truncate temp table*/
DB::table('hs_code_temps')->truncate();
/*Counting rows on a file*/
$original_file_rows_count = $collection->count();
/*Chunk the file data according #var $chunk*/
$chunks = $collection->chunk($this->chunk);
/*read each chunks insert into Temporary table and validate to get if there is error in each row*/
$chunks->each(function ($item) {
/*Iterate on each chunk*/
$item->toArray();
foreach ($item as $row) {
/* start: Validating row entries */
$error_report = "";
$error = 0;
foreach ($row as $key => $value) {
if (trim($key) == $this->hscode_key) {
if (trim($value) == "" Or $value == NULL) {
$error = 1;
$error_report = $error_report . trans('exceptions.backend.upload.entries', ['column' => $key, 'entry' => $value]) . ", \r\n";
$row[$key] = NULL;
}
} elseif (trim($key) == $this->description_key) {
if (trim($value) == "" Or $value == NULL) {
$error = 1;
$error_report = $error_report . trans('exceptions.backend.upload.entries', ['column' => $key, 'entry' => $value]) . ", \r\n";
$row[$key] = NULL;
}
} elseif (trim($key) == $this->regulatory_status_key) {
if (trim($value) == "" Or $value == NULL) {
$error = 1;
$error_report = $error_report . trans('exceptions.backend.upload.entries', ['column' => $key, 'entry' => $value]) . ", \r\n";
$row[$key] = NULL;
}
}
}
/*Inserting into Temp table*/
DB::table('hs_code_temps')->insert([
'code' => $row[$this->hscode_key],
$this->description_key => $row[$this->description_key],
$this->regulatory_status_key => $row[$this->regulatory_status_key],
$this->comment_key => $row[$this->comment_key],
'receipt_code_id' => 1/*$receiptCode->id*/,
'error' => $error,
'error_report' => $error_report,
'created_at' => Carbon::now(),
]);
/* end: Validating row entries*/
}
});
/*compare total rows with no error to total rows of the file*/
$total_temp_rows_count = DB::table('hs_code_temps')->whereError(0)->count();
if ($total_temp_rows_count != $original_file_rows_count) {
/*When there is error and rows are not equal*/
} else {
/*When there is no error*/
$originalHsCode = new Hscode();
$temp_table = DB::table('hs_code_temps')->get(['code', $this->description_key, $this->regulatory_status_key, $this->comment_key])/*->toArray()*/;
/*Iterate throw the rows in a temp row*/
foreach ($temp_table as $object) {
/*copy data from temp table to origin table*/
$originalHsCode->create(get_object_vars($object));
}
/*Truncate temp table*/
DB::table('hs_code_temps')->truncate();
}
}
}
public function headings(): array
{
return ['HSCode','Description','Regulatory_Status','Comment'];
}
/*public function sheets(): array
{
}*/
public function chunkSize(): int
{
return 500;
}
public function batchSize(): int
{
return 500;
}
}
I expect the job to run a large data to a chunk to be processed
pass false as third parameter to chunk() to disable queuing
$data = [];
Excel::filter('chunk')->load($path)->chunk(1000, function ($results) use (&$data) {
foreach ($results as $row) {
$data[] = $row;
}
}, $shouldQueue = false);
return $data;
I have a similar problem when deplying to heroku ,that points to a problem with the path.:
`ERROR: [0] File "/tmp/laravel-excel-4noteGu1gFjJoFClKJQsLw8SgDShm1nd.xlsx"
does not exist. on line 344 of file
vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php`
laravel-excel defines local_path variable in config/excel.php, so try changing the path here or check your public_path() where you are geting the problem.
in my case the excemption saved in table failde_jobs is:
"exception": """ InvalidArgumentException: File "/app/storage/framework/laravel-excel/laravel-excel-aCnUQTJT7ADvAnrf1AOEcaCBPLjhauij" does not exist. in /app/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Shared/File.php:135\n
have been trying to see how to change sot that it does not go in the app folder..
A portion of my Laravel app uses the cli to do batch processing. I'm trying to make a progress bar that will give useful information as to how far along in the process you are. One thing I am doing batch processing on is addresses. I'd like to format it somewhat similar to this:
Processing addresses...
Local Shopping Mall
123 Fake street
Cityville, USA
12345
4/378 [>---------------------------] 1%
After the first address, I'd like to move the cursor back to right after 'Processing addresses...' and I'd like to overwrite the old address with the new one.
Right now, I'm getting this:
Processing addresses...
124 Fake street
Cityville, USA
12345
125 Fake street
Cityville, USA
12345
126 Fake street
Cityville, USA
12345
127 Fake street
Cityville, USA
12345
4/378 [>---------------------------] 1%
Here's the (slightly modified) code I'm using:
public function handle()
{
$this->info('Processing addresses...');
$addresses = \App\Address::all();
$bar = $this->output->createProgressBar(count($addresses));
foreach ($addresses as $address) {
$bar->clear();
$this->info("\r" . $this->_getFormattedAddress($address));
$bar->advance();
sleep(1);
}
}
private function _getFormattedAddress(\App\Address $address){
$out = "";
$out .= $address->address1 . "\n";
$out .= $address->address2 . "\n";
$out .= $address->city . "\n";
$out .= $address->region . "\n";
$out .= $address->iso_code . "\n";
$out .= $address->postal_code . "\n";
return $out;
}
"\r" - return point to start line and $this->info() - add PHP_EOL to end line.
If you need return cursor to top output. I dont know Laravel can do it or not. But this class help you:
class OutputCliHelper
{
protected static $lastLines = 0;
/**
* #param $data
* #return string
*/
public static function replaceSingleLine($data){
return "\r".$data;
}
/**
* #return int
*/
public static function getLastLines()
{
return static::$lastLines;
}
/**
* #param $data
* #param null $lastLines
* #return string
*/
public static function replaceMultiLine($data, $lastLines = null) {
if(!is_null($lastLines)) {
static::$lastLines = $lastLines;
}
$term_width = exec('tput cols', $toss, $status);
if($status) {
$term_width = 64; // Arbitrary fall-back term width.
}
$lineCount = 0;
foreach(explode(PHP_EOL, $data) as $line) {
$lineCount += count(str_split($line, $term_width));
}
$magic = '';
// Erasure MAGIC: Clear as many lines as the last output had.
for($i = 0; $i < static::$lastLines; $i++) {
// Return to the beginning of the line
$magic .= "\r";
// Erase to the end of the line
$magic .= "\033[K";
// Move cursor Up a line
$magic .= "\033[1A";
// Return to the beginning of the line
$magic .= "\r";
// Erase to the end of the line
$magic .= "\033[K";
// Return to the beginning of the line
$magic .= "\r";
// Can be consolodated into
// $magic .= "\r\033[K\033[1A\r\033[K\r";
}
static::$lastLines = $lineCount;
return $magic.$data."\n";
}
}
Now you need get output string (implode PHP_EOL), and call:
$text = "{$id} Fake street\nCityville, USA\n12345";
$progressOutputString = ...;
$yourOutputString = $text.PHP_EOL.$progressOutputString;
echo OutputCliHelper::replaceMultiLine($yourOutputString);
For example:
public function handle()
{
$output = new BufferedOutput(); //Symfony
$progress = new ProgressBar($output); //Symfony
$progress->start(10);
for ($i = 0; $i < 10; $i++) {
$progress->advance();
$tmp = explode(PHP_EOL, $output->fetch());
$string = array_pop($tmp);
echo static::replaceMultiLine($string.PHP_EOL.mt_rand());
}
}
For all users I need to conditionally block access to nodes of type 'message'. The only way users should be able to view these message nodes is by successfully submitting a form.
I've started like this:
function mymodule_node_access($node, $op, $account) {
if ($op == 'view' && $node->type == 'message') {
return NODE_ACCESS_DENY;
}
}
However, I want to allow view access to individual nodes of this type upon successful submission of form:
function form_submit($form, &$form_state) {
// some logic here
$form_state['redirect'] = 'node/255';
}
so node 255 is of type 'message', and I want to 'lift' the NODE_ACCESS_DENY for this particular node and this user (+ in most cases this will be an anonymous user)
Any suggestions on different ways to accomplish this?
The only way you can do that is to set a value in the form submission handler that is then checked by hook_node_access(); you could use a Drupal variable, or a value saved in a database table.
You need to store the user ID of the user that accessed the form, and the node ID of every node for which such form has been submitted.
Supposing you use a Drupal variable, you could use code similar to the following one:
function mymodule_form_submit($form, &$form_state) {
global $user;
$message_nid = 255;
$values = variable_get('access_nid', array());
if (isset($values[$user->uid])) {
if (!isset($values[$user->uid][$message_nid])) {
$values[$user->uid][$message_nid] = $message_nid;
}
}
else {
$values[$user->uid] = array($message_nid => $message_nid);
}
variable_set('access_nid', $values);
$form_state['redirect'] = 'node/' . $message_nid;
}
function mymodule_node_access($node, $op, $account) {
$result = NODE_ACCESS_IGNORE;
if ($op == 'view' && $node->type == 'message') {
$values = variable_get('access_nid', array());
if (!empty($values[$account->uid]) {
if (isset($values[$account->uid][$node->nid])) {
unset($values[$account->uid][$node->nid]);
$result = NODE_ACCESS_ALLOW;
}
else {
$result = NODE_ACCESS_DENY;
}
}
else {
$result = NODE_ACCESS_DENY;
}
}
variable_set('access_nid', $values);
return $result;
}
To notice that this code allows a user to access a node only once; if the user would try to access the same node the second time, the user would get an "access denied" error. If that is not desired, then the second function should be re-written as follows:
function mymodule_node_access($node, $op, $account) {
if ($op == 'view' && $node->type == 'message') {
$values = variable_get('access_nid', array());
if (!empty($values[$account->uid]) {
if (isset($values[$account->uid][$node->nid])) {
return NODE_ACCESS_ALLOW;
}
return NODE_ACCESS_DENY;
}
}
else {
$result = NODE_ACCESS_DENY;
}
}
return NODE_ACCESS_IGNORE;
}
I used a Drupal variable to write simple code; using a Drupal variable, in this case, should be done if the users that can create nodes of that content type are few; if there are many users who can create those nodes, then using a database table is better.
Also when using Drupal variables, Drupal is using a database table; the difference is that the content of that database table is always loaded in memory. If you need to store many data, you should not use Drupal variables.
Modified solution to use $_SESSION as I'm working mostly with anonymous users:
function mymodule_form_submit($form, &$form_state) {
$message_nid = 255;
if (!isset($_SESSION['node_access'])) {
$_SESSION['node_access'] = array();
}
if (!isset($_SESSION['node_access']['nid'])) {
$_SESSION['node_access']['nid'] = $message_nid;
}
$form_state['redirect'] = 'node/' . $message_nid;
}
function mymodule_node_access($node, $op, $account) {
$node_access = NODE_ACCESS_IGNORE;
if ($op == 'view' && $node->type == 'message') {
if (isset($_SESSION['node_access'] && !empty($_SESSION['node_access'])) {
if ($node->nid == $_SESSION['node_access']['nid']) {
unset($_SESSION['node_access']['nid']);
$node_access = NODE_ACCESS_ALLOW ;
} else {
unset($_SESSION['node_access']['nid']);
$node_access = NODE_ACCESS_DENY;
}
} else {
$node_access = NODE_ACCESS_DENY;
}
}
return $node_access;
}
I've been struggling a while in order to get my primary links to display only the first level entries (roots). I have the following code in my template.php :
I've tried changing the $level variable to 0 but no effect. I don't know where (the hell) to stop the recursion.
function supertheme_navigation_links($menu_name, $level = 2) {
// Don't even bother querying the menu table if no menu is specified.
if (empty($menu_name)) {
return array();
}
// Get the menu hierarchy for the current page.
$tree_page = menu_tree_page_data($menu_name);
// Also get the full menu hierarchy.
$tree_all = menu_tree_all_data($menu_name);
// Go down the active trail until the right level is reached.
while ($level-- > 0 && $tree_page) {
// Loop through the current level's items until we find one that is in trail.
while ($item = array_shift($tree_page)) {
if ($item['link']['in_active_trail']) {
// If the item is in the active trail, we continue in the subtree.
$tree_page = empty($item['below']) ? array() : $item['below'];
break;
}
}
}
return supertheme_navigation_links_level($tree_page, $tree_all);
}
/**
* Helper function for supertheme_navigation_links to recursively create an array of links.
* (Both trees are required in order to include every menu item and active trail info.)
*/
function supertheme_navigation_links_level($tree_page, $tree_all) {
$links = array();
foreach ($tree_all as $key => $item) {
$item_page = $tree_page[$key];
$item_all = $tree_all[$key];
if (!$item_all['link']['hidden']) {
$l = $item_all['link']['localized_options'];
$l['href'] = $item_all['link']['href'];
$l['title'] = $item_all['link']['title'];
if ($item_page['link']['in_active_trail']) {
if (empty($l['attributes']['class'])) {
$l['attributes']['class'] = 'active-trail';
}
else {
$l['attributes']['class'] .= ' active-trail';
}
}
if ($item_all['below']) {
$l['children'] = supertheme_navigation_links_level($item_page['below'], $item_all['below']);
}
// Keyed with unique menu id to generate classes from theme_links().
$links['menu-'. $item_all['link']['mlid']] = $l;
}
}
return $links;
}
/**
* Return a themed set of links. (Extended to support multidimensional arrays of links.)
*/
function supertheme_links($links, $attributes = array('class' => 'links')) {
$output = '';
if (count($links) > 0) {
$output = '<ul'. drupal_attributes($attributes) .'>';
$num_links = count($links);
$i = 1;
foreach ($links as $key => $link) {
$class = $key;
// Add first, last and active classes to the list of links to help out themers.
if ($i == 1) {
$class .= ' first';
}
if ($i == $num_links) {
$class .= ' last';
}
if (isset($link['href']) && ($link['href'] == $_GET['q'] || ($link['href'] == '<front>' && drupal_is_front_page()))) {
$class .= ' active';
}
// Added: if the link has child items, add a haschildren class
if (isset($link['children'])) {
$class .= ' haschildren';
}
$output .= '<li'. drupal_attributes(array('class' => $class)) .'>';
if (isset($link['href'])) {
// Pass in $link as $options, they share the same keys.
$output .= l($link['title'], $link['href'], $link);
}
else if (!empty($link['title'])) {
// Some links are actually not links, but we wrap these in <span> for adding title and class attributes
if (empty($link['html'])) {
$link['title'] = check_plain($link['title']);
}
$span_attributes = '';
if (isset($link['attributes'])) {
$span_attributes = drupal_attributes($link['attributes']);
}
$output .= '<span'. $span_attributes .'>'. $link['title'] .'</span>';
}
// Added: if the link has child items, print them out recursively
if (isset($link['children'])) {
$output .= "\n" . theme('links', $link['children'], array());
}
$i++;
$output .= "</li>\n";
}
$output .= '</ul>';
}
return $output;
}
function supertheme_primary_links() {
return supertheme_navigation_links(variable_get('menu_primary_links_source', 'primary-links'
));
}
3 comments:
Not totally sure what you meant when you said you tried to change $level to 0, but then it will not enter in the loop: while ($level-- > 0 && $tree_page)
To be able to stop a recursion, the recursive function needs to have an argument with the depth. So INSIDE the recursive function you decide when to stop: if ($depth <1) { return; } and everytime you call the recursive funcion you call it with $depth-1
If you want this functionality 'out-of-the-box', try http://drupal.org/project/menu_block , or get some inspiration from its code: (see menu_tree_depth_trim function)
I believe, that if you set your menu to be non-expanded under menu settings that Drupal will handle the rest for you.
Another option would be to use nice menus which mainly is used to show expandable menus, but also can be used to control the level of menu expansion.