In my model, a Song is linked to a Type. A Type can be Youtube, Soundcloud, Deezer, etc..
When the link value has been validated by my validator, I want to set the style_id value with the correct Type.
What is the best way to do it ?
I think the best way is to perform the check twice:
first time: using the validator, so you know it's one of these video provider and then return the video link (not the id)
second time: redefine the setLink() so it takes the link, extract the id and save both the link and the style_id
How to do that.
Create a custom lib, like lib/videoProvider.class.php. This is kind of prototyped class to valid & retrieve id from a video provider. It, of course, needs improvements.
class videoProvider
{
private $url;
private $providers = array('youtube','deezer','soundcloud');
private $youtubePattern = '%^# Match any youtube URL
(?:https?://)? # Optional scheme. Either http or https
(?:www\.)? # Optional www subdomain
(?: # Group host alternatives
youtu\.be/ # Either youtu.be,
| youtube\.com # or youtube.com
(?: # Group path alternatives
/embed/ # Either /embed/
| /v/ # or /v/
| /watch\?v= # or /watch\?v=
) # End path alternatives.
) # End host alternatives.
([\w-]{10,12}) # Allow 10-12 for 11 char youtube id.
$%x';
private $deezerPattern = '/\d+/';
private $soundcloudPattern = '[\w-]+/[\w-]+$';
public function __construct($url)
{
$this->url = $url;
}
/**
* #return true / false
*/
private function checkYoutube()
{
return preg_match($this->youtubePattern, $this->url) ? true : false;
}
/**
* #return true / false
*/
private function checkDeezer()
{
// A Deezer URL has this format : http://www.deezer.com/track/61340079
return preg_match($this->deezerPattern, $this->url) ? true : false;
}
/**
* #return true / false
*/
private function checkSoundcloud()
{
// A Soundcloud URL has this format : http://soundcloud.com/[A-Z Artist]/[A-Z Title]
return preg_match($this->soundcloudPattern, $this->url) ? true : false;
}
/**
* #return true / false
*/
public function isValid()
{
// check all video provider as you do in your validator
// so it will return true if it find one, otherwise false
foreach ($this->providers as $provider)
{
$function = 'check'.ucfirst($provider);
if (true === $this->$function())
{
return true;
}
}
return false;
}
/**
* #return string
*/
public function getId()
{
if ($this->checkYoutube() && preg_match($this->youtubePattern, $this->url, $matches))
{
return $matches[1];
}
if ($this->checkDeezer() && preg_match($this->deezerPattern, $this->url, $matches))
{
return $matches[1];
}
if ($this->checkSoundcloud() && preg_match($this->deezerPattern, $this->url, $matches))
{
return $matches[1];
}
}
/**
* #return string
*/
public function getProvider()
{
if ($this->checkYoutube())
{
return 'youtube';
}
if ($this->checkDeezer())
{
return 'deezer';
}
if ($this->checkSoundcloud())
{
return 'soundcloud';
}
}
}
Then in the doClean of your validator, you just need to call this class, like that:
$videoProvider = new videoProvider($url);
if (false === $videoProvider->isValid())
{
throw new sfValidatorError($this, 'invalid', array('value' => $url));
}
return $url;
Finally, the setLink in Song.class.php should now be:
public function setLink($value)
{
// only perform this tweak if the value is a http link
if (preg_match('/^http/i', $value))
{
$videoProvider = new videoProvider($value);
// define url id
parent::_set('link', $videoProvider->getId());
// define type id
$provider = $videoProvider->getProvider();
$type = Doctrine_Core::getTable('Type')->findOneByName($provider);
parent::_set('type_id', $type->getId());
}
}
This is a first draft that must be tested and improved (test if getId() returns an id and not false, same for getProvider, etc ...)
Related
I am using Visual Studio Code(VS Code), it can display the annotation of functios.
I am try to improve write a PHPDoc standard.
Can any suggestions to me? Thank you.
Here have 3 functions, but they are not the focal point .
I just want to know how to write a PHPDoc standard describe the function 2 and simulation overload function 3.
Ref:
https://github.com/phpDocumentor/fig-standards/blob/master/proposed/phpdoc.md#54-examples
<?php
// Function 1:
/**
* Check if A is equal to B.(Just a sample note, not important)
*
* #param string A
* #param string B
*
* #return bool
*/
function checkAandB_1($a, $b){
if($a === $b)
return true;
return false;
}
// Function 2:
/**
* Check if A is equal to B.(Just a sample note, not important)
*
* #param string Input x,y (<=here, I need to known how to write a right note to describe this function can support input a string combin x and y with a comma in one line)
*
* #return bool
*/
function checkAandB_2($str){
if( substr_count($str, ",") === 1 ) {
$strArr = explode(",",$str);
if($strArr[0] === $strArr[1])
return true;
}
return false;
}
// Function 3: Simulation a overload function
/**
* Check if A is equal to B.(Just a sample note, not important)
*
* #param string (What's the best annotation to describe this function?)
*
* #return bool
*/
function checkAandB_overload($str, $b = null){
if(isset($b) && $str === $b){
return true;
}elseif( substr_count($str, ",") === 1 ) {
$strArr = explode(",",$str);
if($strArr[0] === $strArr[1])
return true;
}
return false;
}
var_dump(checkAandB_1("1","2")); // false
var_dump(checkAandB_1("2","2")); // true
var_dump(checkAandB_2("1,2")); // false
var_dump(checkAandB_2("2,2")); // true
var_dump(checkAandB_overload("1","2")); // false
var_dump(checkAandB_overload("2","2")); // true
var_dump(checkAandB_overload("1,2")); // false
var_dump(checkAandB_overload("2,2")); // true
I'm doing a validation by regex from a request, this validation is to check that the parameter that is sent is an IP.
My rules are as follows:
<?php
namespace App\Http\Requests\usuarios;
use Illuminate\Foundation\Http\FormRequest;
class storeVPN extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'segmentwan' => 'regex:/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/',
'segmentlan' => 'regex:/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/',
];
}
the debugger shows me that the error is in this line
the debugger shows me that the error is in this line
return preg_match($parameters[0], $value) > 0;
y el error completo es el siguiente
* #return bool
*/
public function validateRegex($attribute, $value, $parameters)
{
if (! is_string($value) && ! is_numeric($value)) {
return false;
}
$this->requireParameterCount(1, $parameters, 'regex');
return preg_match($parameters[0], $value) > 0;
}
/**
* Validate that a required attribute exists.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function validateRequired($attribute, $value)
{
if (is_null($value)) {
return false;
} elseif (is_string($value) && trim($value) === '') {
return false;
} elseif ((is_array($value) || $value instanceof Countable) && count($value) < 1) {
return false;
} elseif ($value instanceof File) {
return (string) $value->getPath() !== '';
}
In Laravel you have ip validation rule so you can use:
return [
'segmentwan' => 'ip',
'segmentlan' => 'ip',
];
Also to be honest when I'm looking at your code I don't see the error. Are you sure error is with those 2 regexes?
Change your Validation rules. When you are using regex you need to use Array instead of pipe delimiter.
return [
'segmentwan' => [ 'regex:/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/'],
'segmentlan' => [ 'regex:/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/'],
];
Note: When using the regex pattern, it may be necessary to specify
rules in an array instead of using pipe delimiters, especially if the
regular expression contains a pipe character.
UPDATE
If you are validating IP address than laravel provides three validation options.
ip:
The field under validation must be an IP address.
ipv4:
The field under validation must be an IPv4 address.
ipv6:
The field under validation must be an IPv6 address.
You shouldn't be using regex to validate IPs; you can use filter_var() built-in function instead
It has many flags including FILTER_FLAG_IPV4 for ipv4 & FILTER_FLAG_IPV6 for ipv6 ... Ofcourse you can mix flags so you are able to check both
How can I check if the Ethereum address from Laravel input is valid in terms of format?
Here's a Laravel custom validation rule for validating Ethereum addresses against the EIP 55 specification. For details of how it works, please go through the comments.
<?php
namespace App\Rules;
use kornrunner\Keccak; // composer require greensea/keccak
use Illuminate\Contracts\Validation\Rule;
class ValidEthereumAddress implements Rule
{
/**
* #var Keccak
*/
protected $hasher;
public function __construct(Keccak $hasher)
{
$this->keccak = $hasher;
}
public function passes($attribute, $value)
{
// See: https://github.com/ethereum/web3.js/blob/7935e5f/lib/utils/utils.js#L415
if ($this->matchesPattern($value)) {
return $this->isAllSameCaps($value) ?: $this->isValidChecksum($value);
}
return false;
}
public function message()
{
return 'The :attribute must be a valid Ethereum address.';
}
protected function matchesPattern(string $address): int
{
return preg_match('/^(0x)?[0-9a-f]{40}$/i', $address);
}
protected function isAllSameCaps(string $address): bool
{
return preg_match('/^(0x)?[0-9a-f]{40}$/', $address) || preg_match('/^(0x)?[0-9A-F]{40}$/', $address);
}
protected function isValidChecksum($address)
{
$address = str_replace('0x', '', $address);
$hash = $this->keccak->hash(strtolower($address), 256);
// See: https://github.com/web3j/web3j/pull/134/files#diff-db8702981afff54d3de6a913f13b7be4R42
for ($i = 0; $i < 40; $i++ ) {
if (ctype_alpha($address{$i})) {
// Each uppercase letter should correlate with a first bit of 1 in the hash char with the same index,
// and each lowercase letter with a 0 bit.
$charInt = intval($hash{$i}, 16);
if ((ctype_upper($address{$i}) && $charInt <= 7) || (ctype_lower($address{$i}) && $charInt > 7)) {
return false;
}
}
}
return true;
}
}
Dependencies
To validate checksum addresses, we need a Keccac implementation in place which is not supported by the built-in hash() function. You need to require this pure PHP implementation for the above rule to work.
Any 42 character string starting with 0x, and following with 0-9, A-F, a-f (valid hex characters) represent a valid Ethereum address.
You can find more information about lowercase and partial uppercase (for adding checksum) Ethereum addresses format here.
As of Laravel 9, If you are using a request class for validation, add this to the validation rules:
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'address' => 'regex:/^(0x)?(?i:[0-9a-f]){40}$/'
];
}
Notes:
Here, the input field name is address
I applied case insensitivity to only a part of the regular expression using the format (?i: ... )
I'm using PHP and curl with json to interact with my geth server.
I'm able to do all I want except one thing: checking if user's inputted address is valid according to ethereum wallet format.
I saw a javascript function here, but I'm mostly using PHP, I'm not into JS at all.
Any ideas how to validate ethereum addresses in PHP?
Here's a PHP implementation for Ethereum address validation against the EIP 55 specification. For details of how it works, please go through the comments.
<?php
use kornrunner\Keccak; // composer require greensea/keccak
class EthereumValidator
{
public function isAddress(string $address): bool
{
// See: https://github.com/ethereum/web3.js/blob/7935e5f/lib/utils/utils.js#L415
if ($this->matchesPattern($address)) {
return $this->isAllSameCaps($address) ?: $this->isValidChecksum($address);
}
return false;
}
protected function matchesPattern(string $address): int
{
return preg_match('/^(0x)?[0-9a-f]{40}$/i', $address);
}
protected function isAllSameCaps(string $address): bool
{
return preg_match('/^(0x)?[0-9a-f]{40}$/', $address) || preg_match('/^(0x)?[0-9A-F]{40}$/', $address);
}
protected function isValidChecksum($address)
{
$address = str_replace('0x', '', $address);
$hash = Keccak::hash(strtolower($address), 256);
// See: https://github.com/web3j/web3j/pull/134/files#diff-db8702981afff54d3de6a913f13b7be4R42
for ($i = 0; $i < 40; $i++ ) {
if (ctype_alpha($address{$i})) {
// Each uppercase letter should correlate with a first bit of 1 in the hash char with the same index,
// and each lowercase letter with a 0 bit.
$charInt = intval($hash{$i}, 16);
if ((ctype_upper($address{$i}) && $charInt <= 7) || (ctype_lower($address{$i}) && $charInt > 7)) {
return false;
}
}
}
return true;
}
}
Dependencies
To validate checksum addresses, we need a keccak-256 implementation in place which is not supported by the built-in hash() function. You need to require the greensea/keccak composer package as a dependency.
Kudos to #WebSpanner for pointing out the issue with SHA3 hashing.
Basically, you can convert the javascript entirely to PHP.
Here i have been able to convert and test the code for validating an ethereum address in PHP.
/**
* Checks if the given string is an address
*
* #method isAddress
* #param {String} $address the given HEX adress
* #return {Boolean}
*/
function isAddress($address) {
if (!preg_match('/^(0x)?[0-9a-f]{40}$/i',$address)) {
// check if it has the basic requirements of an address
return false;
} elseif (!preg_match('/^(0x)?[0-9a-f]{40}$/',$address) || preg_match('/^(0x)?[0-9A-F]{40}$/',$address)) {
// If it's all small caps or all all caps, return true
return true;
} else {
// Otherwise check each case
return isChecksumAddress($address);
}
}
/**
* Checks if the given string is a checksummed address
*
* #method isChecksumAddress
* #param {String} $address the given HEX adress
* #return {Boolean}
*/
function isChecksumAddress($address) {
// Check each case
$address = str_replace('0x','',$address);
$addressHash = hash('sha3',strtolower($address));
$addressArray=str_split($address);
$addressHashArray=str_split($addressHash);
for($i = 0; $i < 40; $i++ ) {
// the nth letter should be uppercase if the nth digit of casemap is 1
if ((intval($addressHashArray[$i], 16) > 7 && strtoupper($addressArray[$i]) !== $addressArray[$i]) || (intval($addressHashArray[$i], 16) <= 7 && strtolower($addressArray[$i]) !== $addressArray[$i])) {
return false;
}
}
return true;
}
Meanwhile, for someone looking for a very simple regular expression for checking ethereum address validity (e.g to use is as a pattern attribute of an HTML field), this regular expression may suffice.
^(0x)?[0-9a-fA-F]{40}$
Is there a way to match a part of a string within an array in PHP?
I would like to validate a user ip against allowed IPs. Therefore I have created an array with IPs and coresponding partner_id. This works, however I also want to allow an entire subnet and would therefore need to mach against part of the array. Is this possible?
This is my code:
# define partner IPs
$partner_ips = array(
'192.168.56.1' => 0, // dev
'192.168.57.*' => 1 // office ips
);
# test for partner IP and associate partner_id if found
if (array_key_exists($_SERVER['REMOTE_ADDR'], $partner_ips))
$partner_id = $partner_ips[$_SERVER['REMOTE_ADDR']];
else
$partner_id = false;
Thank you for any help on this.
Check the ip format first. Build two different arrays, one for full ip adresses and one for subnets. An example class (feel free to make it PSR-2 compliant, since you use PHP 5.6 you can also declare the two arrays as class constants instead of static variables):
class RemoteAddress {
private $ip;
private $id;
private static $partners_ips = [
'192.168.56.1' => 0,
'192.168.58.4' => 2,
'192.168.59.2' => 3 ];
private static $partners_subnets = [ // note that subnets must end with a dot
'192.168.57.' => 1,
'192.168.60.' => 4,
'192.168.61.' => 5 ];
public function __construct($ip) {
if (filter_var($ip, FILTER_VALIDATE_IP) === false)
throw new Exception("invalid IP address");
$this->ip = $ip;
$this->id = $this->searchID();
}
public function getIDPartner() {
return $this->id;
}
private function searchID() {
if (array_key_exists($this->ip, self::$partners_ips))
return self::$partners_ips[$this->ip];
foreach (self::$partners_subnets as $subnet => $id) {
if (strpos($this->ip, $subnet) === 0)
return $id;
}
return false;
}
}
You can use it like this:
try {
if (isset($_SERVER['REMOTE_ADDR'])) {
$remAddr = new RemoteAddress($_SERVER['REMOTE_ADDR']);
var_dump($remAddr->getIDPartner());
} else throw new Exception('$_SERVER[\'REMOTE_ADDR\'] is not defined');
} catch(Exception $e) {
echo $e->getMessage();
}
You can use in_array for check if your string exist in array or not
http://php.net/manual/en/function.in-array.php