How can I encrypt a Joomla Configuration Parameter that is stored in the database? - joomla

I found this question, which is identical to what I need to do:
How do you Encrypt and Decrypt a PHP String?
I've got everything working to the point of encrypting the data before it is saved. In the event function onExtensionBeforeSave, I have access to the table. I can get the values that need to be encrypted from jinput and encrypt them. What I can't figure out is how to put the encrypted data into the table object in a way that it will replace the un-encrypted data before it is stored/saved.

I was able to figure this out. In the extension event onExtensionBeforeSave, I get the post data, load the config.xml file to check the form fields for my custom fields (type='encryptedtext'), encryt those and use the table object to bind and check it, so it will be stored correctly.
function onExtensionBeforeSave($context, $table, $isNew)
{
$jinput = JFactory::getApplication()->input;
$component = $jinput->get('component');
if($component !== 'com_store') // Only encrypting fields in the store component for now
{
return true;
}
$form_path = JPATH_ADMINISTRATOR . '\\components\\' . $component . '\\config.xml';
$xml = simplexml_load_file($form_path);
$has_encrypted = false;
foreach($xml->fieldset as $fieldset)
{
foreach($fieldset as $field)
{
if($field['type'] == 'encryptedtext') // is our custom form field type to be encrypted
{
$has_encrypted = true;
if(!$fields) // get fields if it hasn't already been done
{
$fields = $jinput->get('jform', '', 'array');
}
$field = (string)$field['name'];
$value = (string)$fields[$field];
$cipher = "aes-256-ctr";
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen, $isStrongCrypto);
if (!$isStrongCrypto)
{
throw new \Exception("Not a strong key");
}
$keyhash = openssl_digest($component, 'sha256', true);
$opts = OPENSSL_RAW_DATA;
$encrypted = openssl_encrypt($value, $cipher, $keyhash, $opts, $iv);
if ($encrypted === false)
{
throw new \Exception('Encryption failed: ' . openssl_error_string());
}
$result = $iv . $encrypted;
$result = base64_encode($result);
$fields[$field] = $result;
}
}
}
if(!has_encrypted)
{
return false;
}
$data = array(
'params'=>$fields,
'option'=>$component
);
if (!$table->bind($data))
{
throw new RuntimeException($table->getError());
}
if (!$table->check())
{
throw new RuntimeException($table->getError());
}
return true;
}
All that is left is to decrypt it in the getInput function of the custom field. I answer this in case someone needs it, and I would love some critique if people see improvements, or if it's complete junk ...

Related

In Drupal, how to validate the contents of a file uploaded using webforms and *not* upload if it fails validation?

I am implementing a site that accepts archives with directory structure in a specific fashion. I want to check the directory structure in the zipfile before accepting it. I tried the following (please see comments inline):
<?php
Using Webform Validation:
// using the webform validation module and its hooks
function testsuite_ziptest_webform_validation_validators()
{
return array(
"validate_zip_file"=> array(
'name' => "testsuite: Validate Zipfile" ,
'component_types' => array(
'select',
'file',
),
'description' => t('Verifies that the contents of the zipfile adhere to the specifications of testsuite.'),
)
);
}
function testsuite_ziptest_webform_validation_validate($validator_name, $items, $components, $rule)
{
$errors = array();
if($items)
{
switch($validator_name)
{
case "validate_zip_file":
drupal_set_message(t('Validate function called'));
foreach($items as $key=>$value)
{
drupal_set_message($key);
$v = _webform_validation_flatten_array($value);
drupal_set_message($v);
}
// tried to get the $fid and access the file using the fid.
// item_6 is the key of the file field that I selected while
// enabling webform validation.
// This fails saying no such file exists when the ziparchive
// object tries to open it.
$fid = $items['item_6'];
if(!empty($fid))
{
$za = new ZipArchive();
$file = file_load($fid);
$za->open($file->uri);
for($i = 0; $i < $za->numFiles; $i++)
{
$stat = $za->statIndex($i);
drupal_set_message($stat['name']);
}
$za->close();
}
break;
}
}
return $errors;
}
Using hook_file_validate
// this works, but there might be other files that may
// be uploaded to the site and I only want it to trigger
// when the file is uploaded as a part of a webform, not
// for all file uploads.
function testsuite_ziptest_file_validate($file)
{
if(!empty($file->filename))
{
$za = new ZipArchive();
$za->open($file->uri);
for($i = 0; $i < $za->numFiles; $i++)
{
$stat = $za->statIndex($i);
drupal_set_message($stat['name']);
}
$za->close();
}
}
Using Forms API (?)
// The following two methods that uses the form api on the webform
// has the same issue as the webform validation module. I can't get
// any reference to the file.
// There is a reference through a "completed form" key but I don't know
// if this is best practice
// die statements were used for debugging
function testsuite_ziptest_form_alter(&$form, &$form_state, $form_id)
{
if($form_id == 'webform_client_form_1')
{
array_unshift($form['#validate'], 'testsuite_ziptest_form_validate');
return $form;
}
}
function testsuite_ziptest_form_validate($form, &$form_state)
{
echo '<pre>'; print_r($form_state); echo '</pre>';
die();
$fid = $form_state['values']['submitted']['attachment'];
if(!empty($fid))
{
$za = new ZipArchive();
$file = file_load($fid);
$za->open($file->uri);
for($i = 0; $i < $za->numFiles; $i++)
{
$stat = $za->statIndex($i);
drupal_set_message($stat['name']);
}
$za->close();
}
else
{
}
die();
return;
}
Thanks!
I think you miss a point when you've done your function. You simply forgot to send the error back.
In the Webforms validation process, you have to send back some elements in the $errors array if something gone wrong.
$errors[$key] = t('%item is not good', array('%item' => $components[$key]['name']));
Here is an example of using this method.
In the Drupal form validation process, you have to use form_set_error if something is not good, with the combo name and the error message. The validation then stop automatically and the form will not be submitted...
And in the hook_file_validate method, you also have to send back an array of errors, witch will be use by the validator to stop the submission (with form_set_error).
Its Working Example :
function yourmoduleNma_file_validate($file,$validators)
{
$errors = array();
$filename = $file->filename;
$isValid_Extention_Size = explode('.',$filename);
if(count($isValid_Extention_Size) > 2){
$errors[] = 'Extention is not valid of this file';
}
elseif($file->filesize <= 0)
{
$errors[] = 'File size should be greater than 0 Bytes and less than 5 MB';
}
return $errors;
}

Adding attribute options programmatically are not available for use immediately

I'm creating Magento attribute options via a script, but I need to then be able to get the new ID and use it straight away in the same script.
At the moment it's not pulling the id through - if I kill the script and re-start it it picks up the created option and returns the ID, but not as part of the same script.
Here is the code I am using:
$attr = Mage::getModel('catalog/product')->getResource()->getAttribute($key);
if ($attr->usesSource()) {
$vattr_id = $attr->getSource()->getOptionId($value);
}else{
echo "No Source";
$vattr_id = false;
}
if($vattr_id){
return $vattr_id;
}else{
$attr_model = Mage::getModel('catalog/resource_eav_attribute');
$attr = $attr_model->loadByCode('catalog_product', $key);
$attr_id = $attr->getAttributeId();
$option['attribute_id'] = $attr_id;
$option['value'][$value][0] = $value;
$option['value'][$value][1] = $value;
$setup = new Mage_Eav_Model_Entity_Setup('core_setup');
$setup->addAttributeOption($option);
$attr = Mage::getModel('catalog/product')->getResource()->getAttribute($key);
if ($attr->usesSource()) {
$vattr_id = $attr->getSource()->getOptionId($value);
echo "AttrID: $vattr_id";
}
}
Running this (with the required Mage::app() etc), creates the option, you can see it in the Magento back end, but the $vattr_id is NULL. If I reload the script, then it finds the attribute option in that first block as it should.
I guess it's something to do with how Magento is caching the models, but not sure where I need to look to clear these?
function getAttributeOptionId($attributeName, $attributeValue) {
/* #var $attribute Mage_Eav_Model_Entity_Attribute */
$attribute = Mage::getModel("eav/entity_attribute")->loadByCode("catalog_product", $attributeName);
// checking attribute code
if ($attribute->getId()) {
$source = $attribute->getSource();
$options = $source->getAllOptions();
// looking for existing id
foreach ($options as $optionValue) {
if ($attributeValue == $optionValue["label"]) {
return $optionValue["value"];
}
}
// making new option
$addOptionData = array(
"attribute_id" => $attribute->getId(),
"value" => array(array($attributeValue))
);
$setup = new Mage_Eav_Model_Entity_Setup('core_setup');
$setup->addAttributeOption($addOptionData);
// getting new id
$attribute = Mage::getModel("eav/entity_attribute")->loadByCode("catalog_product", $attributeName);
$source = $attribute->getSource();
$options = $source->getAllOptions();
foreach ($options as $optionValue) {
if ($attributeValue == $optionValue["label"]) {
return $optionValue["value"];
}
}
}
return null;
}
echo getAttributeOptionId("brand", "Intel");

Joomla 2.5 method save()

Is there a way to show the changed values after saving within the Joomla save method?
For example, when I edit a "maxuser" field and save it, I´d like to show the old and the new value.
I tried this by comparing "getVar" and "$post", but both values are the same.
function save()
{
...
$maxuser1 = JRequest::getVar('maxuser');
$maxuser2 = $post['maxuser'];
...
if($maxuser1 != $maxuser2) {
$msg = "Not the same ...";
}
...
}
It's better to override JTable, not the Model. Heres sample code:
public function store($updateNulls = false) {
$oldTable = JTable::getInstance(TABLE_NAME, INSTANCE_NAME);
$messages = array();
if ($oldTable->load($this->id)) {
// Now you can compare any values where $oldTable->param is old, and $this->param is new
// For example
if ($oldTable->title != $this->title) {
$messages[] = "Title has changed";
}
}
$result = parent::store($updateNulls);
if ((count($messages) > 0) && ($result === true)){
$message = implode("\n", $messages);
return $message;
} else {
return $result;
}
}
This will return message string if there are any, true if there are no messages and save succeeded and false if saving failed. So all you have to do is check returned value in model and set right redirect message.
In the controller you can use the postSaveHook which gives you access to the validated values.

How to prevent code duplication for CodeIgniter form validation?

This is sample of function in the Staff controller for this question
function newStaff()
{
$data = array();
$data['departmentList'] = $this->department_model->list_department();
$data['branchList'] = $this->branch_model->list_branch();
$data['companyList'] = $this->company_model->list_company();
$this->load->view('staff/newstaff', $data);
}
function add_newStaff()
{
//when user submit the form, it will call this function
//if form validation false
if ($this->validation->run() == FALSE)
{
$data = array();
$data['departmentList'] = $this->department_model->list_department();
$data['branchList'] = $this->branch_model->list_branch();
$data['companyList'] = $this->company_model->list_company();
$this->load->view('staff/newstaff', $data);
}
else
{
//submit data into DB
}
}
From the function add_newStaff(), i need to load back all the data from database if the form validation return false. This can be troublesome since I need to maintain two copy of codes. Any tips that I can use to prevent this?
Thanks.
Whats preventing you from doing the following
function newStaff()
{
$data = $this->_getData();
$this->load->view('staff/newstaff', $data);
}
function add_newStaff()
{
//when user submit the form, it will call this function
//if form validation false
if ($this->validation->run() == FALSE)
{
$data = $this->_getData();
$this->load->view('staff/newstaff', $data);
}
else
{
//submit data into DB
}
}
private function _getData()
{
$data = array();
$data['departmentList'] = $this->department_model->list_department();
$data['branchList'] = $this->branch_model->list_branch();
$data['companyList'] = $this->company_model->list_company();
return $data;
}
Alternately you change the action your form submits to so that it points to the same service you use for the initial form request with something like the following. This would also mean that you'd have the POST values retained between page-loads if you wanted to retain any of the submitted values in your form.
function newStaff()
{
// validation rules
if ($this->validation->run() == TRUE)
{
//submit data into DB
}
else
{
$data = array();
$data['departmentList'] = $this->department_model->list_department();
$data['branchList'] = $this->branch_model->list_branch();
$data['companyList'] = $this->company_model->list_company();
$this->load->view('staff/newstaff', $data);
}
}

insert multidimensional array into mysqli db

I'm really hoping someone can help me out before I throw myself off a cliff. I have created a class to upload multiple images stored in a multidimensional array. The images are moved to a selected folder. I want to store the details of each image in a mysqli database. Each image should share a unique key which identifies it to a specific product.
The itm_pic_details (images) table has 5 fields
id auto increment id
itm_pic_id unique id linked to the product
itm_pic_dsc name of file
itm_file_date date added
itm_file_user (not needed to be filled in at this stage. Only for transaction purposes)
itm_file_path (location of image)
I have included the 2 most important functions in my Upload class
protected function processFile($filename,$error,$size, $type,$tmp_name,$overwrite){
$OK = $this->checkError($filename,$error);
if ($OK) {
$sizeOK = $this->checkSize($filename, $size);
$typeOK = $this->checkType($filename, $type);
if ($sizeOK && $typeOK) {
$name = $this->checkName($filename, $overwrite);
$success = move_uploaded_file($tmp_name, $this->_destination . $name);
if ($success) {
$message = "$filename uploaded successfully";
if ($this->_renamed) {
$message .= " and renamed $name";
}
$this->_messages[] = $message;
} else {
$this->_messages[] = 'Could not upload ' . $filename;
}
}
}
}
public function move($overwrite = false) {
$field = current($this->_uploaded);
if(is_array($field['name'])){
foreach($field['name'] as $number => $filename){
//process the multiple upload
$this->_renamed = false;
$this->processFile($filename,$field['error'][$number],$field['size'] [$number],$field['type'][$number],$field['tmp_name'][$number], $overwrite);
}
} else {
$this->processFile($field['name'],$field['error'],$field['size'],$field['type'],$field['tmp_name'],$overwrite);
}
}

Resources