/** * create a new protected file object which has properties that can be used for writing an actual file to * * @param string $name * @return ProtectedFile */ public static function createForWriting($name) { $file = new ProtectedFile(); $file->name = $name; $file->generateUID(); $path = $file->getFilePath(); if (!file_exists($path)) { if (!@mkdir($path, 0755, true)) { throw new Exception("{$path} could not be created: permission denied"); } } return $file; }
public function actionCrop($dims = '1328x560,776x864') { $dimensions = explode(',', $dims); $xy = explode('x', $dimensions[0]); $wh = explode('x', $dimensions[1]); $src_x = $xy[0]; $src_y = $xy[1]; $dest_w = $wh[0]; $dest_h = $wh[1]; // find all cropped images in ophinvisualfields_field_measurement->cropped_image_id: $fields = OphInVisualfields_Field_Measurement::model()->findAll(); foreach ($fields as $field) { $full = ProtectedFile::model()->findByPk($field->image_id); $cropped = ProtectedFile::model()->findByPk($field->cropped_image_id); // if the value isnt set, move on if (!$full || !$cropped) { continue; } // next step, take image_id and open image: if (file_exists($full->getPath())) { $src = imagecreatefromgif($full->getPath()); $dest = imagecreatetruecolor($dest_w, $dest_h); imagecopy($dest, $src, 0, 0, $src_x, $src_y, $dest_w, $dest_h); imagegif($dest, $cropped->getPath()); echo 'patient: ' . $field->getPatientMeasurement()->patient->hos_num . ', path: ' . $cropped->getPath() . PHP_EOL; // Reset sizes $full->size = filesize($full->getPath()); $full->save(); $cropped->size = filesize($cropped->getPath()); $cropped->save(); } } }
public static function fromFhir($fhirObject) { $report = parent::fromFhir($fhirObject); $patient = \Patient::model()->find('id=?', array($report->patient_id)); $report->patient_id = $patient->id; $eye = 'Right'; if ($report->eye == 'L') { $eye = 'Left'; } elseif ($report->eye == 'B') { $eye = 'Both'; } $report->eye_id = \Eye::model()->find('name=:name', array(':name' => $eye))->id; if (isset($fhirObject->xml_file_data)) { $report->xml_file_data = base64_decode($fhirObject->xml_file_data); } $title = $report->file_reference; if (\ProtectedFile::model()->find('name = ?', array($title))) { throw new EverythingsFine("Duplicate filename: {$title} (patient ID {$report->patient_id})"); } $protected_file = \ProtectedFile::createForWriting($title); $protected_file->name = $title; file_put_contents($protected_file->getPath(), base64_decode($report->image_scan_data)); $protected_file->mimetype = 'image/gif'; $protected_file->save(); $cropped_file = \ProtectedFile::createForWriting($title); // all content is base64 encoded, so decode it: file_put_contents($cropped_file->getPath(), base64_decode($report->image_scan_crop_data)); $cropped_file->mimetype = 'image/gif'; $cropped_file->name = $title; $cropped_file->save(); $report->scanned_field_id = $protected_file->id; $report->scanned_field_crop_id = $cropped_file->id; return $report; }
public function actionImport() { echo "<h1>Importing files:</h1>"; foreach (glob(Yii::app()->basePath . '/data/test/*') as $src_file) { $file = ProtectedFile::createFromFile($src_file); if (!$file->save()) { throw new CException('Cannot save file' . print_r($file->getErrors(), true)); } unlink($src_file); echo "<p>Imported " . $file->uid . ' - ' . $file->name . "</p>"; } echo "<p>Done!</p>"; }
/** * abstraction to process FileCollection form. * * @param OphCoTherapyapplication_FileCollection $model * @param string $audit_type */ protected function processFileCollectionForm($model, $audit_type = 'create') { $model->attributes = $_POST['OphCoTherapyapplication_FileCollection']; // validate the model $model->validate(); $transaction = Yii::app()->getDb()->beginTransaction(); // slightly complex rollback process because of files being copied into the protected file store // we want to be able to roll this back as well as the db process. try { $pf_ids = $this->processFileCollectionFileUpload($model, $_FILES['OphCoTherapyapplication_FileCollection_files']); if (!count($model->getErrors())) { if ($model->save()) { // because this might be an update, we get the current files on the model so that we don't remove files // from it $curr_pf_ids = array(); foreach ($model->files as $file) { $curr_pf_ids[] = $file->id; } $model->updateFiles(array_merge($curr_pf_ids, $pf_ids)); Audit::add('admin', $audit_type, $model->id, null, array('module' => 'OphCoTherapyapplication', 'model' => 'OphCoTherapyapplication_FileCollection')); Yii::app()->user->setFlash('success', 'File Collection created'); $transaction->commit(); $this->redirect(array('viewfilecollections')); } } // clear out any protected files that might have been created. $criteria = new CDbCriteria(); $criteria->addInCondition('id', $pf_ids); foreach (ProtectedFile::model()->findAll($criteria) as $pf) { $pf->delete(); } // if we've got this far, something is amiss $transaction->rollback(); } catch (Exception $e) { Yii::log('OphCoTherapyapplication_FileCollection creation error: ' . $e->getMessage(), 'error'); Yii::app()->user->setFlash('error', 'An unexpected error has occurred'); // clear out any protected files that might have been created. $criteria = new CDbCriteria(); $criteria->addInCondition('id', $pf_ids); foreach (ProtectedFile::model()->findAll($criteria) as $pf) { $pf->delete(); } $transaction->rollback(); } }
/** * main method to run the command for file collection creation. * * @TODO: look for a summary text file to include. * @TODO: search for existing file collections and update instead of adding. * * @param array $args * * @return int|void */ public function run($args) { if (!count($args) == 1) { $this->usageError('missing source path argument'); } if (!is_readable($args[0])) { $this->usageError('cannot read specified source path ' . $args[0]); } $base_path = $args[0]; // read directory structure into data $file_list = $this->buildFileList($base_path, './'); $file_ext_regexp = implode('|', $this->file_extensions); $sets = array(); // determine the file collections to be created foreach ($file_list as $fname => $details) { if (preg_match('/' . $file_ext_regexp . '$/', $fname)) { $path = str_replace(DIRECTORY_SEPARATOR, ' - ', dirname($fname)); if (!@$sets[$path]) { $summary_text = $this->summary_text_default; $summary_filepath = $base_path . dirname($fname) . DIRECTORY_SEPARATOR . $this->summary_filename; if ($this->summary_filename && file_exists($summary_filepath)) { // read the summary text in from the file $summary_text = file_get_contents($summary_filepath); } $sets[$path] = array('summary' => $summary_text, 'files' => array($details)); } else { $sets[$path]['files'][] = $details; } } } $created = 0; $modified = 0; // iterate through and create the file collections. foreach ($sets as $set_name => $set_details) { $created_flag = false; $transaction = Yii::app()->getDb()->beginTransaction(); $pf_list = array(); $pf_ids = array(); try { foreach ($set_details['files'] as $details) { $pf = ProtectedFile::createFromFile($details['source']); if ($pf->save()) { $pf_ids[] = $pf->id; $pf_list[] = $pf; } else { foreach ($pf_list as $pf) { $pf->delete(); } break; } } // update the existing file collection if there is one $criteria = new CDbCriteria(); $criteria->addCondition('name = :nm'); $criteria->params = array(':nm' => $set_name); if (!($fc = OphCoTherapyapplication_FileCollection::model()->find($criteria))) { $fc = new OphCoTherapyapplication_FileCollection(); $fc->name = $set_name; $created_flag = true; } $fc->summary = $set_details['summary']; if (!$fc->validate()) { echo "unexpected validation error with file collection\n"; var_dump($fc->getErrors()); $transaction->rollback(); } else { if ($fc->save()) { $fc->updateFiles($pf_ids); Audit::add('admin', 'create', $fc->id, null, array('module' => 'OphCoTherapyapplication', 'model' => 'OphCoTherapyapplication_FileCollection')); $transaction->commit(); $created_flag ? $created++ : $modified++; } else { foreach ($pf_list as $pf) { $pf->delete(); } $transaction->rollback(); } } } catch (Exception $e) { echo $e->getMessage(); foreach ($pf_list as $pf) { $pf->delete(); } $transaction->rollback(); } } echo 'Processing complete, ' . $created . ' collections created, ' . $modified . " collections updated\n"; }
public function getDecryptedSignature($signature_pin) { if ($signature_pin) { if ($this->signature_file_id) { $signature_file = ProtectedFile::model()->findByPk($this->signature_file_id); $image_data = base64_decode($this->decryptSignature(file_get_contents($signature_file->getPath()), md5(md5($this->id) . $this->generateUniqueCodeWithChecksum($this->getUniqueCode()) . $signature_pin))); if (strlen($image_data) > 100) { return $image_data; } } } return false; }
/** * Store the PDF as a ProtectedFile in the system * * @return ProtectedFile * @throws Exception */ public function storePDF() { $pf = ProtectedFile::createFromFile($this->outDir . '/' . $this->outFile); $pf->save(); $this->cleanUp(); return $pf; }
/** * Trawl an existing OE database and find all files that match the given * pattern. A pattern MUST be specified. * * If no pattern is specified, all images that match the standard humphrey * image size are processed. */ public function actionRedact($pattern = null) { $criteria = new CDbCriteria(); if ($pattern != null) { $criteria->condition = 'name like :name'; $criteria->params = array(':name' => $pattern); } else { echo 'You MUST specify a file pattern to match.'; } $files = ProtectedFile::model()->findAll($criteria); // we can't really filter images, except on size - for now just // assume the count is half the amount when taking thumbnails into // consideration echo count($files) / 2 . ' files found for modification.'; if ($files) { foreach ($files as $file) { if (file_exists($file->getPath())) { $this->anonymiseTif($file->getPath()); } else { echo 'Could not transform file; ' . $file->getPathName() . ' does not exist.' . PHP_EOL; } } } }
public function actionImport($importDir, $archiveDir, $errorDir, $dupDir, $interval = 'PT45M', $pasImport = false) { $this->importDir = $this->checkSeparator($importDir); $this->archiveDir = $this->checkSeparator($archiveDir); $this->errorDir = $this->checkSeparator($errorDir); $this->dupDir = $this->checkSeparator($dupDir); $this->interval = $interval; $fhirMarshal = Yii::app()->fhirMarshal; $eventType = EventType::model()->find('class_name=:class_name', array(':class_name' => 'OphInVisualfields')); if (!$eventType) { echo 'Cannot find OphInVisualfields event type, cannot continue' . PHP_EOL; die; } echo 'Processing FMES files...' . PHP_EOL; $filenames = glob($this->importDir . '/*.fmes'); echo count($filenames) . " files to process\n"; foreach ($filenames as $file) { try { $basename = basename($file); echo $basename . PHP_EOL; // First check the file has not already been imported: $field = file_get_contents($file); $fieldObject = $fhirMarshal->parseXml($field); if ($protected_file = ProtectedFile::model()->find('name=:name', array(':name' => $fieldObject->file_reference))) { echo '- ProtectedFile exists (' . $protected_file->id . ')' . PHP_EOL; $this->move($this->dupDir, $file); continue; } // Extract the patient number $matches = array(); preg_match('/__OE_PATIENT_ID_([0-9]*)__/', $field, $matches); if (count($matches) < 2) { echo '- Failed to extract patient ID' . PHP_EOL; $this->move($this->errorDir, $file); continue; } $match = str_pad($matches[1], 7, '0', STR_PAD_LEFT); // Fetch the patient if ($pasImport) { $model = new Patient(null); $model->hos_num = $match; $results = $model->search()->getData(); $patient = reset($results); } else { $patient = Patient::model()->find('hos_num=:hos_num', array(':hos_num' => $match)); } if (!$patient) { echo "- Failed to find patient ({$match})" . PHP_EOL; $this->move($this->errorDir, $file); continue; } $pid = $patient->id; $field = preg_replace('/__OE_PATIENT_ID_([0-9]*)__/', $pid, $field); // Convert to measurement $resource_type = 'MeasurementVisualFieldHumphrey'; $service = Yii::app()->service->getService($resource_type); $fieldObject = $fhirMarshal->parseXml($field); $tx = Yii::app()->db->beginTransaction(); $ref = $service->fhirCreate($fieldObject); $tx->commit(); $refId = $ref->getId(); $measurement = OphInVisualfields_Field_Measurement::model()->findByPk($refId); $study_datetime = $measurement->study_datetime; // Check for existing legacy events if (!($episode = Episode::model()->find('legacy = 1 AND patient_id = :patient_id', array(':patient_id' => $pid)))) { echo '- No legacy episode found, creating...'; $episode = new Episode(); $episode->legacy = 1; $episode->patient_id = $pid; $episode->save(); echo 'done' . PHP_EOL; // As there are no previous legacy events, we can create a new event $this->newEvent($episode, $eventType, $measurement); $this->move($this->archiveDir, $file); } else { // There is a legacy episode, so there may be unmatched legacy field events $criteria = new CdbCriteria(); $criteria->condition = 'event_type_id = :event_type_id and t.deleted = 0 and ep.deleted = 0 and ep.legacy = 1 and ep.patient_id = :patient_id'; $criteria->join = 'join episode ep on ep.id = t.episode_id'; $criteria->order = 't.event_date desc'; $criteria->params = array(':patient_id' => $pid, ':event_type_id' => $eventType->id); if ($this->interval) { // we're looking for all events that are bound to a legacy episode, // for the given patient, looking for the last created test - // this accounts for multiple tests per eye - the implication // being that the newest test overrides the last test for the same eye // (e.g. when a mistake is made and the test is re-ran): // Base time on interval defined by user, a narrow time slot that the test falls within $startCreatedTime = new DateTime($study_datetime); $endCreatedTime = new DateTime($study_datetime); $startCreatedTime->sub(new DateInterval($this->interval)); $endCreatedTime->add(new DateInterval($this->interval)); $criteria->condition .= ' AND t.event_date >= STR_TO_DATE("' . $startCreatedTime->format('Y-m-d H:i:s') . '", "%Y-%m-%d %H:%i:%s") AND t.event_date <= STR_TO_DATE("' . $endCreatedTime->format('Y-m-d H:i:s') . '", "%Y-%m-%d %H:%i:%s")'; } // Of events, there can only be one or none: // FIXME: This can return multiple events, so how do we choose? $events = Event::model()->findAll($criteria); if (count($events) == 1) { echo '- Found existing event (' . $events[0]->id . ')' . PHP_EOL; $element = Element_OphInVisualfields_Image::model()->find('event_id = :event_id', array(':event_id' => $events[0]->id)); $side = strtolower($measurement->eye->name); if ($existing = $element->{"{$side}_field"}) { if ($measurement->study_datetime > $existing->study_datetime) { echo "Newer than existing measurement on {$side}, overwriting\n"; $element->{"{$side}_field_id"} = $measurement->id; $unattached = $existing; } else { echo "Older than existing measurement on {$side}, ignoring\n"; $unattached = $measurement; } // Add dummy reference for the unattached measurement $ref = new MeasurementReference(); $ref->patient_measurement_id = $unattached->getPatientMeasurement()->id; $ref->save(); } else { echo "No existing measurement on {$side}, adding\n"; $element->{"{$side}_field_id"} = $measurement->id; } $element->save(); $this->move($this->archiveDir, $file); } elseif (count($events) > 1) { echo '- Found more than one matching event, cannot attach' . PHP_EOL; $this->move($this->errorDir, $file); } else { // No events in match window, so we create a new one $this->newEvent($episode, $eventType, $measurement); $this->move($this->archiveDir, $file); } } } catch (Exception $ex) { echo $ex . PHP_EOL; if (@$tx && $tx->active) { echo '- rolling back tx' . PHP_EOL; $tx->rollback(); } $this->move($this->errorDir, $file); } } }
/** * create the PDF file as a ProtectedFile for the given side. * * @param CController $controller * @param array $template_data * @param string $side * * @throws Exception * * @return ProtectedFile|null */ protected function createAndSavePdfForSide(CController $controller, array $template_data, $side) { if ($html = $this->getPDFContentForSide($controller, $template_data, $side)) { $html = '<link rel="stylesheet" type="text/css" href="' . $controller->assetPath . '/css/print.css" />' . "\n" . $html; $this->event->lock(); if (!$this->event->hasPDF('therapy_application')) { $wk = new WKHtmlToPDF(); $wk->setDocuments(1); $wk->setDocRef($this->event->docref); $wk->setPatient($this->event->episode->patient); $wk->setBarcode($this->event->barcodeHTML); $wk->generatePDF($this->event->imageDirectory, 'event', 'therapy_application', $html, false, false); } $this->event->unlock(); if (@$_GET['html']) { return Yii::app()->end(); } $pfile = ProtectedFile::createForWriting('ECForm - ' . $side . ' - ' . $template_data['patient']->hos_num . '.pdf'); if (!@copy($this->event->getPDF('therapy_application'), $pfile->getPath())) { throw new Exception('Unable to write to file: ' . $pfile->getPath()); } if (!$pfile->save()) { throw new Exception('Unable to save file: ' . print_r($pfile->errors, true)); } return $pfile; } return; }
/** * removes the compressed file association for this collection. Should be called when the files for it are * changed so that a new compressed file is created when needed. * * will also call the delete function on the protected file itself to remove orphaned files */ protected function cleanCompressedFile() { // note we have to work on the file id not the relation if ($id = $this->zipfile_id) { $this->zipfile_id = null; if ($this->save()) { $pf = ProtectedFile::model()->findByPk($id); try { $pf->delete(); } catch (Exception $e) { // ignore this exception as it's because the compressed file is referenced elsewhere } } } }