yii2 saveAs two files, saves only one - file-upload

i dont know why, but i have form where i specify two uploads (preview, detail) and when im trying to save them, detail is saved but preview not. Db has results as i expect - saved $slug in column imageSrc and imageDetailSrc
const UPLOAD_FILE_URL = 'uploads/recipes/';
const UPLOAD_FILE_DETAILS_URL = self::UPLOAD_FILE_URL.'details/';
$filePath = self::UPLOAD_FILE_URL . $slug . '.' . $this->imageSrc->extension;
$filePathDetail = self::UPLOAD_FILE_DETAILS_URL . $slug . '.' . $this->imageDetailSrc->extension;
if ($this->imageSrc->saveAs($filePath) && $this->imageDetailSrc->saveAs($filePathDetail)) {
$this->imageSrc = $slug . '.' . $this->imageSrc->extension;
$this->imageDetailSrc = $slug . '.' . $this->imageDetailSrc->extension;
}
if ($this->save(false, ['imageSrc', 'imageDetailSrc'])) {
return true;
}

Yii2 official documentation states that saveAs function uses move_uploaded_file() function to move the temporary file. Hence the temporary file gets deleted when you call saveAs function for the first time. If you do not want saveAs to delete then you should do send false as the second parameter to your saveAs function.
const UPLOAD_FILE_URL = 'uploads/recipes/';
const UPLOAD_FILE_DETAILS_URL = self::UPLOAD_FILE_URL.'details/';
$filePath = self::UPLOAD_FILE_URL . $slug . '.' . $this->imageSrc-
>extension;
$filePathDetail = self::UPLOAD_FILE_DETAILS_URL . $slug . '.' . $this->imageDetailSrc->extension;
if ($this->imageSrc->saveAs($filePath, false) && $this->imageDetailSrc->saveAs($filePathDetail)) {
$this->imageSrc = $slug . '.' . $this->imageSrc->extension;
$this->imageDetailSrc = $slug . '.' . $this->imageDetailSrc->extension;
}
if ($this->save(false, ['imageSrc', 'imageDetailSrc'])) {
return true;
}

Related

Behat (+ Mink) Check for some text followed by some text (in sibling elements)

The I should see... function is an essential feature of Behat but I regularly find myself wanting to write something like this in my scenarios:
Then I should see "Session ID" followed by "3"
Which is my humanly-parsable way of describing 2 pieces of text next to each other in the content. That is to say the first string is the content of any element and the second is the content of it's next immediate sibling.
This would be useful for checking label - value type layouts:
Or if I want to check header - cell value type layouts in tabulated data:
Or even definition title - definition.
Obviously I could add 'id' attributes to every element I want to test but in a complicated page where many parts of the content need testing this starts to feel like I am bloating the markup with single-use attributes.
To be able to use...
Then I should see "Session ID" followed by "3"
Add the following methods to your FeatureContext.php file:
/**
* #Then I should see :textA followed by :textB
*/
public function iShouldSeeFollowedBy($textA, $textB)
{
$content = $this->getSession()->getPage()->getContent();
// Get rid of stuff between script tags
$content = $this->removeContentBetweenTags('script', $content);
// ...and stuff between style tags
$content = $this->removeContentBetweenTags('style', $content);
$content = preg_replace('/<[^>]+>/', ' ',$content);
// Replace line breaks and tabs with a single space character
$content = preg_replace('/[\n\r\t]+/', ' ',$content);
$content = preg_replace('/ {2,}/', ' ',$content);
if (strpos($content,$textA) === false) {
throw new Exception(sprintf('"%s" was not found in the page', $textA));
}
$seeking = $textA . ' ' . $textB;
if (strpos($content,$textA . ' ' . $textB) === false) {
// Be helpful by finding the 10 characters that did follow $textA
preg_match('/' . $textA . ' [^ ]+/',$content,$matches);
throw new Exception(sprintf('"%s" was not found, found "%s" instead', $seeking, $matches[0]));
}
}
/**
* #param string $tagName - The name of the tag, eg. 'script', 'style'
* #param string $content
*
* #return string
*/
private function removeContentBetweenTags($tagName,$content)
{
$parts = explode('<' . $tagName, $content);
$keepers = [];
// We always want to keep the first part
$keepers[] = $parts[0];
foreach ($parts as $part) {
$subparts = explode('</' . $tagName . '>', $part);
if (count($subparts) > 1) {
$keepers[] = $subparts[1];
}
}
return implode('', $keepers);
}

Is there a syntax error in this iCalendar event code?

I have a 'Subscribed Calendar' on my iPhone which fetches calendar events in the iCalendar format from a URL. The calendar works fine except it does not show the following event, is there a reason why? All other events show fine. I'm thinking there's maybe a problem with the way the event is formatted/syntax but I can't seem to find anything that may be causing it.
BEGIN:VEVENT SUMMARY:Meet with tenant DESCRIPTION:Notes: Meter readings\, SoC images\, post box key\, finalise Let Procedure.\nLocation: Apartment X X Woodland Road\, Bebington\, Wirral\, CHXX XXX\nEmployee: Michael Le Brocq\nStatus: Confirmed\nOriginally Arranged: 07/09/16 12:18:43 by Lucy Christian\nLast Updated: 12/09/16 15:57:05 by Michael Le Brocq\n UID:2432 STATUS:CONFIRMED DTSTART:20160914T160000 DTEND:20160914T151500 LAST-MODIFIED:20160912T155705 LOCATION:Apartment 5 20 Woodland Road\, Bebington\, Wirral\, CH42 4NT END:VEVENT
Code used to generate calendar events;
<?php
require_once('../inc/app_top_cron.php');
if (!empty($_GET)) {
// define and escape each GET as a variable
foreach ($_GET as $key => $value) {
if (!empty($value)) {
${$key} = mysqli_real_escape_string($con, PrepareInput($value));
}
}
}
// company details
$company_details_query = mysqli_query($con, "SELECT company_id, company_trading_name FROM company WHERE company_token = '" . $company . "' LIMIT 1") or die(mysql_error());
$company_details = mysqli_fetch_array( $company_details_query );
// the iCal date format. Note the Z on the end indicates a UTC timestamp.
define('DATE_ICAL', 'Ymd\THis');
// max line length is 75 chars. New line is \\r\n
$output = "BEGIN:VCALENDAR
METHOD:PUBLISH
VERSION:2.0
PRODID:-//Property Software//Calendar//EN
CALSCALE:GREGORIAN
X-WR-CALNAME:" . $company_details['company_trading_name'] . " Calendar" . "
\r\n";
$sql = "SELECT ce.*, ces.calendar_event_status_name
FROM calendar_event ce
INNER JOIN calendar_event_status ces
on ce.calendar_event_status = ces.calendar_event_status_id
WHERE ce.calendar_event_company_id = '" . $company_details['company_id'] . "'";
$calendar_event_query = mysqli_query($con, $sql) or die(mysql_error());
while($row = mysqli_fetch_array( $calendar_event_query )) {
$calendar_event_subject = str_replace(",","\,", $row['calendar_event_subject']);
$calendar_event_description = str_replace(",","\,", $row['calendar_event_description']);
$calendar_event_description = str_replace("\r\n","\\n", $calendar_event_description);
$calendar_event_location = str_replace(",","\,", $row['calendar_event_location']);
// loop through events
$output .=
"BEGIN:VEVENT
SUMMARY:" . $calendar_event_subject . "
DESCRIPTION:" . $calendar_event_description . "
UID:" . $row["calendar_event_id"] . "
STATUS:" . $row["calendar_event_status_name"] . "
DTSTART:" . date(DATE_ICAL, strtotime($row["calendar_event_start"])) . "
DTEND:" . date(DATE_ICAL, strtotime($row["calendar_event_end"])) . "
LAST-MODIFIED:" . date(DATE_ICAL, strtotime($row["calendar_event_date_updated"])) . "
LOCATION:" . $calendar_event_location . "
END:VEVENT
";
}
// close calendar
$output .= "END:VCALENDAR";
echo $output;
mysqli_close($con);
?>
This:
$calendar_event_description = str_replace("\r\n","\\n", $calendar_event_description);
You're taking \r\n (carriage return + newline) and turning them into a literal \ character, followed by an n. That's not a new line (one byte/character), it's TWO bytes/characters, and has no special meaning to anything.
And as per my comments above, don't do multiline string building/concatenating. it makes for hard-to-read and hard-to-follow debugging. Use a heredoc instead:
$output = <<<EOL
BEGIN:VEVENT
SUMMARY: {$calendar_event_subject}
DESCRIPTION: {$calendar_event_description}
UID: {$row["calendar_event_id"]}
etc...
EOL;
Note the lack of any " or . - making for a much more compact and easy-to-follow code block. If you need to change the line breaks afterwards, because your system uses something different than what your code editor is embedding, you can do that with a simple str_replace() after finishing building the string.
The icalendar standard requires \r\n line breaks between lines. You can validate the icalendar output using the validator at http://icalendar.org/validator.html

Yii2 - rename file on upload if the file with the same name exist

How can I rename file if the file with the same name exist (prevent overwrite)? This method is used for uploading file:
// Upload user avatar
public function upload()
{
if ($this->validate()):
$this->avatar->saveAs('../web/images/avatars/' . $this->avatar->baseName . '.' . $this->avatar->extension);
return true;
endif;
return false;
}
Test if file exists with php function and then assign a proper name to your file:
$cnt = 1;
while (file_exists(string $filename)) {
$filename = $this->avatar->basename . $cnt;
$cnt++;
}
Then save.

Rename screenshots taken on failure in PHPUnit Selenium

PHPUnit has an option to take a screenshot upon a Selenium test case failure. However, the screenshot filename generated is a hash of something - I don't know what exactly. While the test result report allows me to match a particular failed test case with a screenshot filename, this is troublesome to use.
If I could rename the screenshot to use the message from the failed assert as well as a timestamp for instance, it makes the screenshots much easier to cross-reference. Is there any way to rename the generated screenshot filename at all?
You could try something like this (it's works with selenium2):
protected function tearDown() {
$status = $this->getStatus();
if ($status == \PHPUnit_Runner_BaseTestRunner::STATUS_ERROR || $status == \PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE) {
$file_name = sys_get_temp_dir() . '/' . get_class($this) . ':' . $this->getName() . '_' . date('Y-m-d_H:i:s') . '.png';
file_put_contents($file_name, $this->currentScreenshot());
}
}
Also uncheck
protected $captureScreenshotOnFailure = FALSE;
I ended up using a modified version of #sectus' answer:
public function onNotSuccessfulTest(Exception $e) {
$file_name = '/' . date('Y-m-d_H-i-s') . ' ' . $this->getName() . '.png';
file_put_contents($this->screenshotPath . $file_name, base64_decode($this->captureEntirePageScreenshotToString()));
parent::onNotSuccessfulTest($e);
}
Although the conditional check in tearDown() works fine, based on Extending phpunit error message, I decided to go with onNotSuccessfulTest() as it seemed cleaner.
The filename could not accept colons :, or I would get an error message from file_get_contents: failed to open stream: Protocol error
The function currentScreenshot also did not exist, so I ended up taking the screenshot in a different way according to http://www.devinzuczek.com/2011/08/taking-a-screenshot-with-phpunit-and-selenium-rc/.
Another method I played around with, as I still wanted to use $this->screenshotUrl and $this->screenshotPath for convenient configuration:
I overwrote takeScreenshot from https://github.com/sebastianbergmann/phpunit-selenium/blob/master/PHPUnit/Extensions/SeleniumTestCase.php
protected function takeScreenshot() {
if (!empty($this->screenshotPath) &&
!empty($this->screenshotUrl)) {
$file_name = '/' . date('Y-m-d_H-i-s') . ' ' . $this->getName() . '.png';
file_put_contents($this->screenshotPath . $file_name, base64_decode($this->captureEntirePageScreenshotToString()));
return 'Screenshot: ' . $this->screenshotUrl . '/' . $file_name . ".png\n";
} else {
return '';
}
}

Can anyone help me with this error

if (isset($_POST['Software'])) {
$_POST['Software']['sw_icon'] = $model->sw_icon;
$model->attributes = $_POST['Software'];
$uploadedFile = CUploadedFile::getInstance($model, 'sw_icon');
$model->attributes = $_POST['Software'];
$model->updated_date = date("Y-m-d H:i");
if ($model->save()) {
if (!empty($uploadedFile)) { // check if uploaded file is set or not
$uploadedFile->saveAs(Yii::app()->basePath . '/../images/software_icons/' . $model->sw_icon);
}
Yii::app()->user->setFlash('success', 'Software updated successfully.');
$this->redirect(array('index'));
}
}
When I use the above code i get the following error
...move_uploaded_file(): The second argument to copy() function
cannot be a directory.
Can you show me the result of Yii::app()->basePath . '/../images/software_icons/' . $model->sw_icon,seems like it a directory
You can move a file to another file name. You can't move a file to a folder.
Try replace Yii::app()->basePath . '/../images/software_icons/' . $model->sw_icon on
this: Yii::app()->basePath . '/../images/software_icons/newfile'