respect validation translation issue - respect-validation

I have been using respect validation 1.1 and I used below code for translating messages.
foreach ($rules as $field => $rule) {
try {
$localeField = $translator->trans($field);
$rule->setName($localeField)->assert($request->getParam($field));
} catch (NestedValidationException $e) {
$translateMessage = function($message) use ($translator){
return $translator->trans($message);
};
$e->setParam('translator', $translateMessage);
$this->errors[$field] = $e->getMessages();
}
Now I'm using respect validation version 2.2 and in this version there is no setParam function for error object.
So I'm wondering how I'm able to translate messages in this version.
Please help!
thanks in advance.

Translation of messages is a bit different in the new version, since you have to use a factory to declare how the default instance is built.
I include here an example that I found in the Respect/Validation integration tests:
use Respect\Validation\Exceptions\ValidationException;
use Respect\Validation\Factory;
use Respect\Validation\Validator;
Factory::setDefaultInstance(
(new Factory())
->withTranslator(static function (string $message): string {
return [
'{{name}} must be of type string' => '{{name}} deve ser do tipo string',
][$message];
})
);
try {
Validator::stringType()->length(2, 15)->check(0);
} catch (ValidationException $exception) {
echo $exception->getMessage();
}
What you will see here as output is the 0 deve ser do tipo string string.

Related

Validating array in Laravel using custom rule with additional parameter

I'm working with Laravel 5.7 and I need to validate a phone length by using 2 inputs (prefix+number). The total digits has to be 10 always.
I'm using this custom rule for other projects which works fine:
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class PhoneLength implements Rule
{
public $prefix;
/**
* Create a new rule instance.
*
* #return void
*/
public function __construct($prefix = null)
{
//
$this->prefix = $prefix;
}
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
//
return strlen($this->prefix)+strlen($value) == 10 ? true : false;
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'El Teléfono debe contener 10 dígitos (prefijo + número)';
}
}
In my controller I do something like
$validatedData = $request->validate([
'prefix' => 'integer|required',
'number' => ['integer','required', new PhoneLength($request->prefix)],
]);
Now I need to make use of arrays, so my new validation looks like
$validatedData = $request->validate([
'phones.*.prefix' => 'required',
'phones.*.number' => ['required', new PhoneLength('phones.*.prefix')],
]);
The above code doesn't work at all, the parameter is not being sent as expected.
How can I send an array value? Of course I need to get the values from the same array element, so if phones[0].number is under validation, the prefix phones[0].prefix is needed.
I've found this question, but I refuse to believe that is not possible to do in a "native" way:
Laravel array validation with custom rule
Thanks in advance
You could get $prefix from the request itself:
class PhoneLength implements Rule
{
public function passes($attribute, $value)
{
$index = explode('.', $attribute)[1];
$prefix = request()->input("phones.{$index}.prefix");
}
}
or pass the $request in the PhoneLength rule constructor, then use it.
The Abdeldayem Sherif's answer is good but there is a problem when the attribute has more level of nesting, for example: clients.*.phones.*.prefix. In this case, exploding and using the 1 index will cause an unexpected error. A better solution is using str_replace.
class PhoneLength implements Rule
{
public function passes($attribute, $value)
{
$prefixAttr = str_replace('.number', '.prefix', $attribute);
$prefix = request()->input($prefixAttr);
}
}
According to this https://github.com/laravel/framework/pull/18654 you can use, it will add your custom rule as dependent and replace asterix with needed indexes
Validator::extendDependent('contains', function ($attribute, $value, $parameters, $validator) {
// The $parameters passed from the validator below is ['*.provider'], when we imply that this
// custom rule is dependent the validator tends to replace the asterisks with the current
// indices as per the original attribute we're validating, so *.provider will be replaced
// with 0.provider, now we can use array_get() to get the value of the other field.
// So this custom rule validates that the attribute value contains the value of the other given
// attribute.
return str_contains($value,
array_get($validator->getData(), $parameters[0])
);
});
Validator::make(
[['email' => 'test#mail.com', 'provider' => 'mail.com']],
['*.email' => 'contains:*.provider']
)->validate();

Laravel 5.2 API Rest and Angular JS - $HTTP_RAW_POST_DATA is deprecated

I am trying to send an $http.post AJAX data to a route configured in Laravel 5.2, everything works perfect, but the server returns this error:
Deprecated: Automatically populating $HTTP_RAW_POST_DATA is deprecated
and will be removed in a future version. To avoid this warning set
'always_populate_raw_post_data' to '-1' in php.ini and use the
php://input stream instead. in Unknown on line 0
Warning: Cannot modify header information - headers already sent in
Unknown on line 0
This is my code. PHP:
public function save(Request $request){
$input = $request->all();
try {
$direccion = urlencode($input['Calle']." ".$input['Numero'].", ".$input['Ciudad']);
$geocode = "https://maps.googleapis.com/maps/api/geocode/json?address=$direccion&key=APIKEY";
$datosGoogle = json_decode($this->curl($geocode), true);
$latitud = $datosGoogle['results'][0]['geometry']['location']['lat'];
$longitud = $datosGoogle['results'][0]['geometry']['location']['lng'];
if(is_double($latitud) && is_double($latitud)){
$input['Latitud'] = $latitud;
$input['Longitud'] = $longitud;
$new = MyModel::create($input);
$data = ["status"=>"ok", "message"=>"Agregado correctamente"];
}else{
$data = ["status"=>"fail", "message"=>"Dirección desconocida, compruebe que los datos son correctos para que podamos agregarla al sistema."];
}
} catch (Exception $e) {
$data = ["status"=>"error", "message"=>$e->getMessage()];
}
return response()->JSON($data);
}
JS:
$scope.registrar = function(form, datos) {
$scope.submitted = true;
if(form.$valid) {
var toSendData = JSON.stringify({
Nombre: datos.nombre,
Calle: datos.calle,
Numero: datos.numero,
Piso: datos.piso,
Puerta: datos.puerta,
CP: datos.cp,
Ciudad: datos.ciudad,
Email: datos.email,
Necesidades: datos.necesidades,
Telefono: datos.telefono
});
console.log(toSendData);
$http.post($rootScope.recibirNuevoUrl, toSendData).then(function(response){
$scope.hideLoading();
if(response.data.status == "ok"){
$state.go('registro');
}else{
$scope.$parent.showAlert("Error al introducir los datos", response.data.message);
}
})
}else{
$scope.$parent.showAlert('Validacion de datos', 'El formulario contiene errores. Por favor revise los campos marcados para comprobar los errores.');
}
};
How can I fix it?
I had the same problem with Laravel 5.2 and Angular, I got it working by adding a single line in my controller:
editorApp.controller('EditorCtrl', function ($scope, $sce, $http, $location, $interval, $document){
$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
...
I found this working for me in this post: https://stackoverflow.com/a/19254137/4021927. The answer marked as correct did not work for me, the line above is from an other answer in the same post. The correct answer (https://stackoverflow.com/a/20276775/4021927) does tell you why you need it though.
In short why this problem exist is because Angular (By default) send data using JSON serialization: Content-Type: application/json and PHP does not unserialize JSON natively. By changing content-type to x-www-form-urlencoded the data will be sent as:
foo=bar&bar=foo
instead of (JSON):
{ "foo": "bar", "bar": "foo" }
I got similar problem retrieving $GLOBALS['HTTP_RAW_POST_DATA'] in Laravel 5.2. I solved the issue by using Request::getContent() in my controller
Got mine working after turning off error_reporting in php.ini
Open php.ini
Search for error_reporting
Change it to => error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
Exit and Start / Restart apache server
Restart laravel server
laravel 5.2
/resource/assets/js/bootstrap.js
window.axios = require('axios');
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = window.Laravel.csrfToken;
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
//add default Content-Type
window.axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
2 data mast be string
const qs = require('qs')
axios.post('/api/code/create', qs.stringify(this.formItem),)
.then(function (response) {
console.log(response)
})
.catch(function (error) {
console.log(error)
})

How to get MIME type of a file in PHP 5.5?

I am using mime_content_type() in PHP 5.5 to get a MIME type, but it throws fatal: error function not found.
How can I achieve this on PHP 5.5?
Make use of the finfo() functions.
A simple illustration:
<?php
$finfo = finfo_open(FILEINFO_MIME_TYPE);
echo finfo_file($finfo, "path/to/image_dir/image.gif");
finfo_close($finfo);
OUTPUT :
image/gif
Note : Windows users must include the bundled php_fileinfo.dll DLL file in php.ini to enable this extension.
I've spent too much time trying to get the finfo functions to work, properly. I finally just ended up creating my own function to match the file extension to any array of mime types. It's not a full-proof way of assuring that the files are truly what the extension denotes them to be, but that problem can be mitigated by how you process I/O of said files on your server(s).
function mime_type($file) {
// there's a bug that doesn't properly detect
// the mime type of css files
// https://bugs.php.net/bug.php?id=53035
// so the following is used, instead
// src: http://www.freeformatter.com/mime-types-list.html#mime-types-list
$mime_type = array(
"3dml" => "text/vnd.in3d.3dml",
"3g2" => "video/3gpp2",
"3gp" => "video/3gpp",
"7z" => "application/x-7z-compressed",
"aab" => "application/x-authorware-bin",
"aac" => "audio/x-aac",
"aam" => "application/x-authorware-map",
"aas" => "application/x-authorware-seg",
"abw" => "application/x-abiword",
"ac" => "application/pkix-attr-cert",
"acc" => "application/vnd.americandynamics.acc",
"ace" => "application/x-ace-compressed",
"acu" => "application/vnd.acucobol",
"adp" => "audio/adpcm",
"aep" => "application/vnd.audiograph",
"afp" => "application/vnd.ibm.modcap",
"ahead" => "application/vnd.ahead.space",
"ai" => "application/postscript",
"aif" => "audio/x-aiff",
"air" => "application/vnd.adobe.air-application-installer-package+zip",
"ait" => "application/vnd.dvb.ait",
"ami" => "application/vnd.amiga.ami",
"apk" => "application/vnd.android.package-archive",
"application" => "application/x-ms-application",
// etc...
// truncated due to Stack Overflow's character limit in posts
);
$extension = \strtolower(\pathinfo($file, \PATHINFO_EXTENSION));
if (isset($mime_type[$extension])) {
return $mime_type[$extension];
} else {
throw new \Exception("Unknown file type");
}
}
Edit:
I'd like to address Davuz's comment (since it keeps getting up-voted) and remind everyone that I put in the pseudo disclaimer at the top that this isn't "full-proof." So, please keep that in mind when considering the approach I've offered in my answer.
mime_content_type() is not deprecated and works fine.
Why is mime_content_type() deprecated in PHP?
http://php.net/manual/en/function.mime-content-type.php
As of PHP 5.3, it's even built-in.
$finfo = finfo_open(FILEINFO_MIME_TYPE); should do it.
Taken from the php.net docs. Your function is deprecated and probably already removed.
http://www.php.net/manual/en/function.finfo-file.php
You should understand that file_get_contents will upload whole file to the memory, it is not good way to get only mime type. You don't need to use buffer method and file_get_contents function in this case.
To prevent any errors and warnings, better do like this.
$filename = 'path to your file';
if (class_exists('finfo')) {
$finfo = new finfo(FILEINFO_MIME_TYPE);
if (is_object($finfo)) {
echo $finfo->file($filename);
}
} else {
echo 'fileinfo did not installed';
}
Also you should know $finfo->file will throw PHP Warning if it fail.
If fileinfo is not installed properly, and you have a fresh version of PHP, you can get mime type from headers.
You can use cURL to get mime type from headers.
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_HEADER => true,
CURLOPT_NOBODY => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 1,
CURLOPT_URL => $link)
);
$headers = curl_exec($ch);
curl_close($ch);
if (preg_match('/Content-Type:\s(.*)/i', $headers, $matches)) {
echo trim($matches[1], "\t\n\r");
}else {
echo 'There is no content type in the headers!';
}
Also you can use get_headers function, but it more slow than cURL request.
$url = 'http://www.example.com';
$headers = get_headers($url, 1);
echo $headers['Content-Type'];
Get the image size using:
$infFil=getimagesize($the_file_name);
and
echo $infFil["mime"]
The getimagesize returns an associative array which have a MIME key and obviously the image size too
I used it and it works
I use the MimeTypeTool from Bat (https://github.com/lingtalfi/Bat)
It uses fileinfo if available, and defaults back to an "extension => mime type" mapping otherwise.
This is the best solution I found by combining two very good posts
// Thanks to http://php.net/manual/en/function.mime-content-type.php#87856
function getMimeContentType($filename, $ext)
{
if(!function_exists('mime_content_type'))
{
if($mime_types = getMimeTypes())
{
if (array_key_exists($ext, $mime_types))
{
return $mime_types[$ext];
}
elseif (function_exists('finfo_open'))
{
$finfo = finfo_open(FILEINFO_MIME);
$mimetype = finfo_file($finfo, $filename);
finfo_close($finfo);
return $mimetype;
}
}
return 'application/octet-stream';
}
return mime_content_type($filename);
}
// Thanks to http://php.net/manual/en/function.mime-content-type.php#107798
function getMimeTypes()
{
$url = 'http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types';
$mimes = array();
foreach(#explode("\n",#file_get_contents($url)) as $x)
{
if(isset($x[0]) && $x[0]!=='#' && preg_match_all('#([^\s]+)#', $x, $out) && isset($out[1]) && ($c = count($out[1])) > 1)
{
for($i=1; $i < $c; $i++)
{
$mimes[$out[1][$i]] = $out[1][0];
}
}
}
return (#sort($mimes)) ? $mimes : false;
}
Use it link this:
$filename = '/path/to/the/file.pdf';
$ext = strtolower(array_pop(explode('.',$filename)));
$content_type = getMimeContentType($filename, $ext);
Will continue to work even if the mime_content_type function is no longer supported in php.

Joomla Component error - Fatal error

I have installed a ticket module on my Joomla website, I get the following error when a ticket is submitted
Fatal error: Call to undefined method JRegistry::getValue() in /home/xboxfifa/public_html/HD/components/com_jtaghelpdesk/controller.php on line 300
function mailme($formData){
$version = new JVersion();
$body = "A new inquiry has been recieved: <br /> Name : ". $formData['inqName']. "<br /> Email ID : ". $formData['inqEmail']. "<br/> Message : ".$formData['inqMessage'] ;
$mailer =& JFactory::getMailer();
$config =& JFactory::getConfig();
if($version->RELEASE==3.0)
{
$recipient = array(
$config->get('mailfrom'),
$config->get('fromname'));
}else
{
$recipient = array(
$config->getValue( 'config.mailfrom' ),
$config->getValue( 'config.fromname' ));
}
$mailer->addRecipient($recipient);
$subject=$formData['inqSubject'];
$mailer->setSubject($subject);
$mailer->isHTML(true);
$mailer->Encoding = 'base64';
$mailer->setBody($body);
$send =& $mailer->Send();
if ( $send !==true )
{ $msg = 'Reply not Sent!';
} else
{
$msg = 'Reply Sent Successfully!';
}
}
If anyone could help me I would appreciate it.
JRegistry::getvalue() was removed in Joomla 3.x so make sure you use JRegistry::get() instead.
As for your version compare, you should use this:
if (version_compare(JVERSION, '3.0.0', 'ge')){
// code here
}
Editing this answer because I realized the issue is something else. The problem here is the $version check you're doing looks for the release to be EXACTLY == 3.0. When really you want that get() method to be used for 3.0 and up. You should change your if-statement to:
if($version->RELEASE >= 3.0)
{ ... }
Because you're using 3.2.1 this will use the proper method gets for that version.

How can I convert validation error field names to input names in CakePHP?

I have a CakePHP (latest version) web app with forms and validation all working properly using traditional postback, but now I'm switching some of the forms to submit via ajax. When there are validation errors, I would like to get them back on the client as JSON formatted like so:
{
"success":false,
"errors":{
"data[User][username]":["This is not a valid e-mail address"],
"data[User][password]":["You must choose a password"]
}}
The keys for the errors array need to correspond to the name attribute on the form fields. We have some prebuilt client script that is expecting JSON formatted in this way. The good news is that this is very close to what the validationErrors object looks like in CakePHP. So I'm currently doing this in my controller:
if ($this->User->save($this->request->data)) {
} else {
if ($this->request->is('ajax')) {
$this->autoRender = $this->layout = false;
$response['success'] = false;
$response['errors'] = $this->User->validationErrors;
echo json_encode($response);
exit(0);
}
}
However, this is what the JSON response looks like:
{
"success":false,
"errors":{
"username":["This is not a valid e-mail address"],
"password":["You must choose a password"]
}}
Note that the errors keys have just the basic database table field names in them. They are not converted into data[User][username] format, which the FormHelper usually takes care of.
Is there some easy way to adjust the array before I return it? I don't want to simply loop through and prepend "data[User]" because that is not robust enough. I'd like some code I can put in one place and call from various controllers for various models. What does FormHelper use to come up with the input name attributes? Can I tap into that? Should I somehow use a JSON view?
That's because that's the way the $validationErrors array is formatted. To obtain the output you want you will have to loop through, there's no way around it.
foreach ($this->User->validationErrors as $field => $error) {
$this->User->validationErrors["data[User][$field]"] = $error;
unset($this->User->validationErrors[$field]);
}
I would suggest instead passing all errors to json_encode(). $this->validationErrors is a combined list of all model validation errors for that request available on the view (compiled after render). You should move your display logic (echoing json) into your view, and loop through it there.
in the view
$errors = array();
foreach ($this->validationErrors as $model => $modelErrors) {
foreach ($modelErrors as $field => $error) {
$errors["data[$model][$field]"] = $error;
}
}
$response['errors'] = $errors;
echo json_encode($response);
This would output something like this:
{
"success":false,
"errors": [
"data[User][username]": "This is not a valid e-mail address",
"data[User][password]": "This is not a valid password",
"data[Profile][name]": "Please fill in the field"
]
}
I have created a small recursive function to create validation error as a string with column name so that can be passed as json object.
/**
* prepare erorr message to be displayed from js
*
* #param array $errors validation error array
* #param stringn $message refernce variable
*
* #return void
*/
public function parseValidationErrors($errors, &$message)
{
foreach ($errors as $columnName => $error) {
$message .= "<strong>$columnName:</strong> ";
foreach ($error as $i => $msg) {
if (is_array($msg)) {
$this->_parseValidationErrors($msg, $message);
} else {
$message .= str_replace("This field", "", $msg . " ");
isset($error[$i + 1]) ? $message .= " and " : $message;
}
}
}
}
and controller code goes like this.
if (!$this->YourModel->saveAll($modelObject)) {
$errors = $this->YourModel->validationErrors;
$message = '';
$this->parseValidationErrors($errors, $message);
$response = array('status' => 'error', 'message' => $message);
}
$response['errors']['User'] = $this->User->validationErrors;

Resources