I can't get PHPUnit's Code Coverage tool to mark this else statement as covered even though it must be or the following line could not be covered. Elsewhere in the same class another line that contains only } else { is correctly marked as covered.
if (is_string($externalId) && $externalId != '') {
$sitesIds[] = $externalId;
} else if ($regionName != null && $regionName != '') {
$sitesIds = $this->sitesService->getSites($regionName);
if (!is_array($sitesIds) || count($sitesIds) == 0) {
throw new \Exception(self::NO_MATCHING_REGION, '404');
}
} else {
throw new \Exception(self::BAD_REQUEST.'. Should specify station or region', '400');
}
Since else doesn't actually do anything (it can be considered just a label) it won't get covered.
Your problem is that you don't have a test where (is_string($externalId) && $externalId != '') is false, ($regionName != null && $regionName != '') is true and (!is_array($sitesIds) || count($sitesIds) == 0) is false. (You might want to be more specific by using not exactly equal to !== instead of not equal to !=: ($externalId !== '') & ($regionName !== null && $regionName !== ''))
If you can get $sitesIds = $this->sitesService->getSites($regionName); to return an array with at least one element, your red line will be covered and turn green.
The red line is telling you that the closing brace } before the else is technically reachable, but you have no tests that cover it.
With slightly modified source:
class A
{
const NO_MATCHING_REGION = 1;
const BAD_REQUEST = 2;
private $sitesService = ['a' => ['AA'], 'b'=>12];
public function a($externalId, $regionName)
{
$sitesIds = [];
if (is_string($externalId) && $externalId != '') {
$sitesIds[] = $externalId;
} else {
if ($regionName != null && $regionName != '') {
$sitesIds = $this->sitesService[$regionName];
if (!is_array($sitesIds) || count($sitesIds) == 0) {
throw new \Exception(self::NO_MATCHING_REGION, '404');
}
} else {
throw new \Exception(self::BAD_REQUEST.'. Should specify station or region', '400');
}
}
return $sitesIds;
}
}
The test
class ATest extends \PHPUnit_Framework_TestCase
{
/**
* #dataProvider data
*/
public function testOk($id, $reg, $res)
{
$a = new A;
$r = $a->a($id, $reg);
$this->assertEquals($res, $r);
}
public function data()
{
return [
['a', 1, ['a']],
[1,'a', ['AA']]
];
}
/**
* #dataProvider error
* #expectedException \Exception
*/
public function testNotOK($id, $reg)
{
$a = new A;
$a->a($id, $reg);
}
public function error()
{
return [
[1,'b'],
[1,null]
];
}
}
Covers the else line:
PHP 5.6.15-1+deb.sury.org~trusty+1
PHPUnit 4.8.21
Related
I am developing a Register/Login system with validation. Registering system is working well. For example, when I register the same email twice, the following message appears:
Email already registered!
However, when I log-in with the same e-mail and password, an error occurs. The following message appears as a validation error:
Email not registered!
Even if the email is registered in DB.
Code for e-mail validation:
<?php
public function validateEmail($par)
{
if (filter_var($par, FILTER_VALIDATE_EMAIL)) {
return true;
} else {
$this->setErro("Invalid Email!");
return false;
}
}
public function validateIssetEmail($email, $action = null)
{
$b = $this->cadastro->getIssetEmail($email);
if ($action == null) {
if ($b > 0) {
$this->setErro("Email already registered!");
return false;
} else {
return true;
}
} else {
if ($b > 0) {
return true;
} else {
$this->setErro("Email not registered!");
return false;
}
}
}
Code for login controller:
<?php
$validate = new Classes\ClassValidate();
$validate->validateFields($_POST);
$validate->validateEmail($email);
$validate->validateIssetEmail($email,"login");
$validate->validateStrongSenha($senha);
$validate->validateSenha($email,$senha);
var_dump($validate->getErro());
Code for class login:
<?php
namespace Models;
class ClassLogin extends ClassCrud
{
# Returns user data
public function getDataUser($email)
{
$b = $this->selectDB(
"*",
"users",
"where email=?",
array(
$email
)
);
$f = $b->fetch(\PDO::FETCH_ASSOC);
$r = $b->rowCount();
return $arrData = [
"data" => $f,
"rows" => $r
];
}
}
My getIssetEmail method exists on Register code only.
# Check directly at the bank if the email is registered
public function getIssetEmail($email)
{
$b = $this->selectDB(
"*",
"users",
"where email=?",
[
$email
]
);
return $r = $b->rowCount(); // returns the amount of rows in the search
}
And ClassPassword
<?php
namespace Classes;
use Models\ClassLogin;
class ClassPassword
{
private $db;
public function __construct()
{
$this->db = new ClassLogin();
}
# Create password's hash to save in DB
public function passwordHash($senha)
{
return password_hash($senha, PASSWORD_DEFAULT);
}
# Verify if password's hash is correct
public function verifyHash($email, $senha)
{
$hashDb = $this->db->getDataUser($email);
return password_verify($senha, $hashDb["data"]["senha"]);
}
}
This is not an answer but hopefully it will help in debugging.
First, I'm going to change your code. This is 100% a style choice but I personally think it is easier to follow. If you have an if statement that always returns, you don't technically need an else. Once again, this is a style choice and you don't have to follow it.
Second, if you can, try adding logging into your workflow, it will save you so much time debugging. It isn't always an option, especially for legacy code bases, but it is awesome when you can inspect complex code. In this example, I"m just making a couple of helper methods that dump stuff but normally I'd use something like Monolog to write to a stream that I can tail, and I can easily turn it off in production. When logging, sometimes it helps to avoid identical messages so that you can easily find the exact line number you are on, too.
So with those changes, try running this code inside of your class:
private function logMessage($message)
{
echo $message . PHP_EOL;
}
private function logVariable($variable)
{
var_dump($variable);
}
public function validateIssetEmail($email, $action = null)
{
$this->logVariable($email);
$this->logVariable($action);
$b = $this->cadastro->getIssetEmail($email);
$this->logVariable($b);
if ($action === null) {
$this->logMessage('Action was null');
if ($b > 0) {
$this->logMessage('B is greater than zero');
$this->setErro("Email already registered!");
return false;
}
$this->logMessage('B was not greater than zero');
return true;
}
$this->logMessage('Action was not null');
if ($b > 0) {
$this->logMessage('B is greater than zero');
return true;
}
$this->logMessage('B was not greater than zero');
$this->setErro("Email not registered!");
return false;
}
This should log in human-readable form every step. You should be able to walk through this and identify where your bug is. For instance, in the comments above you said that a variable was 0 in a block that was guarded by a check that guarantees that that shouldn't happen.
This is the wrong part i guess you assigned login as action so you can call cadastro class inside of the function
$cadastro = new Cadastro();
$b = $cadastro->getIssetEmail($email);
if ($action == null) {
if ($b > 0) {
$this->setErro("Email already registered!");
return false;
} else {
return true;
}
} else {
if ($b > 0) {
return true;
} else {
$this->setErro("Email not registered!");
return false;
}
}
So I am getting the following error.
Fatal error: Call to undefined method CI_Form_validation::error_array() in /home/kmgpdev/public_html/projects/lm/application/controllers/api.php on line 64
Line 63 through 66 reads
if($this->form_validation->run() == false) {
$this->output->set_output(json_encode(['result' => 0, 'error' => $this->form_validation->error_array()]));
return false;
}
If I remove the 64th line it works fine, just no errors are produced.
Also here is my MY_Form_validation.php file I created as a custom library.
class MY_Form_validation extends CI_Form_validation
{
public function __construct($config = array())
{
parent::__construct($config);
}
public function error_array()
{
if(count($this->_error_array > 0)) {
return $this->_error_array;
}
}
}
So it running well in localhost, xampp and when I upload to my ubuntu server then it happend this error, I cannot figure out why this error is coming up. I'm using php 5.5, Any suggestions?
Thanks in advance.
To get the first error message, I have put a utility function like this directly under //system/libraries/Form_validation.php. Otherwise you can use $this->form_validation->error_string() instead of directly picking error array. In most cases, you would want your user to see the error as a string :
function first_error_string($prefix = '', $suffix = '')
{
// No errrors, validation passes!
if (count($this->_error_array) === 0)
{
return '';
}
if ($prefix == '')
{
$prefix = $this->_error_prefix;
}
if ($suffix == '')
{
$suffix = $this->_error_suffix;
}
// Generate the error string
$str = '';
foreach ($this->_error_array as $val)
{
if ($val != '')
{
$str .= $prefix.$val.$suffix;
break;
}
}
return $str;
}
Is there a way to implement method pointers in PHP?
I keep getting the following error:
Fatal error: Call to undefined function create_jpeg() in /Users/sky/Documents/images.php on line 175
This is line 175:
if ($this->ImageType_f[$pImageType]($pPath) != 0)
class CImage extends CImageProperties
{
private $Image;
private $ImagePath;
private $ImageType;
private function create_jpeg($pFilename)
{
if (($this->Image = imagecreatefromjepeg($pFilename)) == false)
{
echo "TEST CREATION JPEG\n";
echo "Error: ".$pFilename.". Creation from (JPEG) failed\n";
return (-1);
}
return (0);
}
private function create_gif($pFilename)
{
if (($this->Image = imagecreatefromgif($pFilename)) == false)
{
echo "Error: ".$pFilename.". Creation from (GIF) failed\n";
return (-1);
}
return (0);
}
private function create_png($pFilename)
{
if (($this->Image = imagecreatefrompng($pFilename)) == false)
{
echo "Error: ".$pFilename.". Creation from (PNG) failed\n";
return (-1);
}
return (0);
}
function __construct($pPath = NULL)
{
echo "Went through here\n";
$this->Image = NULL;
$this->ImagePath = $pPath;
$this->ImageType_f['JPEG'] = 'create_jpeg';
$this->ImageType_f['GIF'] = 'create_gif';
$this->ImageType_f['PNG'] = 'create_png';
}
function __destruct()
{
if ($this->Image != NULL)
{
if (imagedestroy($this->Image) != true)
echo "Failed to destroy image...";
}
}
public function InitImage($pPath = NULL, $pImageType = NULL)
{
echo "pPath: ".$pPath."\n";
echo "pImgType: ".$pImageType."\n";
if (isset($pImageType) != false)
{
if ($this->ImageType_f[$pImageType]($pPath) != 0)
return (-1);
return (0);
}
echo "Could not create image\n";
return (0);
}
}
Just call the method you need with $this->$method_name() where $method_name is a variable containing the method you need.
Also it is possible using call_user_func or call_user_func_array
What is callable is described here: http://php.net/manual/ru/language.types.callable.php
So assuming $this->ImageType_f['jpeg']' must be callable: array($this, 'create_jpeg').
Alltogether: call_user_func($this->ImageType_f[$pImageType], $pPath) is the way to do it.
Or if $this->ImageType_f['jpeg'] = 'create_jpeg':
$this->{$this->ImageType_f['jpeg']]($pPath);
Some documentation on functions I mentioned here:
http://us2.php.net/call_user_func
http://us2.php.net/call_user_func_array
Your problem is is line:
if ($this->ImageType_f[$pImageType]($pPath) != 0)
-since $this->ImageType_f[$pImageType] will result in some string value, your call will be equal to call of global function, which does not exists. You should do:
if ($this->{$this->ImageType_f[$pImageType]}($pPath) != 0)
-but that looks tricky, so may be another good idea is to use call_user_func_array():
if (call_user_func_array([$this, $this->ImageType_f[$pImageType]], [$pPath]) != 0)
I think you need to use this function call_user_func
In your case call will looks like
call_user_func(array((get_class($this), ImageType_f[$pImageType]), array($pPath));
I'm developing an app that will look up an email inbox and save specific emails as part of it's functionality. What happens is an imap connection is made and then all emails that are set as UNSEEN are retrieved. Each email is checked against pre-defined conditions and then saved to a DB if they are met. These conditions can be set by the user and can be the following:
Subject
Contains string
Does not contain string
Body
Contains string
Does not contain string
From
Specific address
Conditions can be "chained" for instance:
FILTER WHERE
Subject CONTAINS "Order Confirmation"
AND
Email FROM "billyjones26#gmail.com" OR "billyjones26#googlemail.com"
I'm having trouble thinking of how to format and store these conditions. I need to have a GUI where the user can create these conditions.
My questions is how should I store these conditions? I.e some sort of DB table structure, or maybe converted into a string format and stored in a single table. There needs to be a unlimited number of conditions for an unlimited number of users, and I need to know what operators there are, etc.
Hope that's enough information!
* EDIT FOR MICHAEL *
So I can create the conditions and save them. Now I'm retrieving them and trying to match emails. I created a filter with one condition: Subject contains 'TEST'. Only one email should match this but somehow all emails are being added to the matched array.
My controller that is getting the emails/conditions:
public function check_email(){
$filters = $this->filters_model->get_filters($owner_id=1);
foreach($filters->result() as $filter){
$emails = $this->gmail->get_emails($mailbox_id = $filter->mailbox_id, $limit = 10);
$matched = array();
$conditions = unserialize($filter->conditions);
foreach($emails as $email){
if($conditions->isMet($email) == TRUE){
$matched[] = $email;
}
}
echo count($matched);
echo '<pre>'.$filter->title.'<br /.';
print_r($conditions);
echo '</pre><br />-----';
exit;
}
}
Keyvalueprerequisite.php
This seems to work fine as a var_dump of stripos($subject, $this->value) !== FALSE; shows only TRUE for 1 email.
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Keyvalueprerequisite {
private $key;
private $comparator;
private $value;
public function __construct($key, $comparator, $value){
$this->key = $key;
$this->comparator = $comparator;
$this->value = $value;
}
public function isMet(&$context)
{
switch ($this->key) {
case "subject":
$subject = $context["subject"];
if ($this->comparator === "in"){
return stripos($subject, $this->value) !== FALSE;
} else if ($this->comparator === "!in") {
return stripos($subject, $this->value) === FALSE;
}
return FALSE;
break;
case "body":
$body = $context["body"];
if ($this->comparator === "in") {
return stripos($body, $this->value) !== FALSE;
} else if ($this->comparator === "!in") {
return stripos($body, $this->value) === FALSE;
}
return FALSE;
break;
case "from_address":
$from = $context["from"];
if ($this->comparator === "=") {
return $this->value === $from;
} else if ($this->comparator === "!=") {
return $this->value !== $from;
} else{
return false;
}
break;
default:
}
return FALSE;
}
}
Prerequisistegroup.php
Something might not be quite write here. a var_dump of $result = $result && $is_met returns true for each of the 10 emails.
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Prerequisitegroup {
private $type;
private $prerequisites;
public function __construct($type = 'AND'){
$this->type = $type;
}
public function add(){
foreach(func_get_args() as $prerequisite){
$this->prerequisites[] = $prerequisite;
}
}
public function isMet(&$context)
{
if (empty($this->prerequisites) === FALSE) {
$result = TRUE;
foreach ($this->prerequisites as $prerequisite) {
$is_met = $prerequisite->isMet($context);
if ($this->type === 'AND') {
$result = $result && $is_met;
if ($result === FALSE) {
return FALSE;
}
} else {
$result = $result || $is_met;
if ($result === TRUE) {
return TRUE;
}
}
}
return $result;
}
return TRUE;
}
}
These are my conditions that are being checked:
string(3) "AND"
["prerequisites":"Prerequisitegroup":private]=>
array(1) {
[0]=>
object(Prerequisitegroup)#23 (2) {
["type":"Prerequisitegroup":private]=>
string(2) "OR"
["prerequisites":"Prerequisitegroup":private]=>
array(1) {
[0]=>
object(Keyvalueprerequisite)#24 (3) {
["key":"Keyvalueprerequisite":private]=>
string(7) "subject"
["comparator":"Keyvalueprerequisite":private]=>
string(2) "in"
["value":"Keyvalueprerequisite":private]=>
string(4) "TEST"
}
}
}
}
}
For a CMS I solved a similar problem, by abstracting the conditions (Prerequisites) into two classes: Prerequisite and PrerequisiteGroup (a subclass of the former, and then serialized them, or more precisely the object, since there would only be one into a BLOB in MySQL.
The advantage of this was that I could simply deserialize the object and invoke an isMet() function without bothering about the depth or complexity of the perquisites. The disadvantage was of course that I couldn't make DB queries on this objects. But that wasn't a problem in this particular case, and from your own suggestions I think it isn't in yours as well.
The Prerequisite class (or interface) implements one method isMet($context) that tells you where your condition is true or not. The context in your case would be the $email to be examined. E.g. if from email matches "billyjones26#gmail.com".
The PrerequisiteGroup represents AND and OR, in a simplified way. The default way to group conditions is by
Here is an example of creating and storing the conditions:
$c1 = new KeyValuePrerequisite("EmailFrom", "=", "billyjones26#gmail.com");
$c2 = new KeyValuePrerequisite("EmailFrom", "=", "billyjones26#googlemail.com");
$c3 = new KeyValuePrerequisite("Subject", "in", "Order Confirmation");
$from_condition = new PrerequisiteGroup('or');
$from_condition->add($c1, $c2);
$final_condition = new PrerequisiteGroup($c3, $from_condition); // defaults to and
$db->query("INSERT INTO conditions SET user_id = %i, conditions = %l", $user_id, serialize($final_condition));
Here is an example usage:
// Fetch conditions
$email_conditions = $user->getEmailConditions()
// Connect to your inbox and fetch relevant emails
$matching_emails = array();
foreach ($emails as $email) {
if ($email_conditions->isMet($email) {
$matching_emails[] = $email;
}
}
Prerequisite interface:
interface Prerequisite
{
/**
* Must return TRUE or FALSE.
*/
public function isMet(&$context);
}
KeyValuePrerequisite implementation (in my implementation this actually an abstract class but for your purpose you can implement everything here, you could call it EmailPrerequisite or EmailCondition):
class KeyValuePrerequisite extends PrerequisiteGroup
{
protected $key;
protected $comparator;
protected $value;
public function __construct($key, $comparator, $value = NULL)
{
$this->key = $key;
$this->comparator = $comparator;
$this->value = $value;
}
public function isMet(&$context)
{
switch ($this->key) {
case "Subject":
$subject = $context["subject"];
if ($this->comparator === "in") }
return stripos($subject, $this->value) !== FALSE;
} else if ($this->comparator === "not int") {
return stripos($subject, $this->value) === FALSE;
}
return FALSE;
break;
case "EmailFrom":
$from = $context["from"];
return $this->value === $from;
break;
default:
}
return FALSE;
}
}
PrerequisiteGroup implementation:
class PrerequisiteGroup implements Prerequisite
{
private $type;
private $prerequisites;
public function __construct($type = 'AND')
{
$this->type = $type;
}
public function add(Prerequisite $prerequisite)
{
if ($prerequisite instanceof Prerequisite) {
$this->prerequisites[] = $prerequisite;
} else {
throw new Exception('Unknown Prerequisite type ' . get_class($prerequisite));
}
}
public function isMet(&$context)
{
if (empty($this->prerequisites) === FALSE) {
$result = $this->type === 'AND';
foreach ($this->prerequisites as $prerequisite) {
$is_met = $prerequisite->isMet($context);
if ($this->type === 'AND') {
$result = $result && $is_met;
if ($result === FALSE) {
return FALSE;
}
} else {
$result = $result || $is_met;
if ($result === TRUE) {
return TRUE;
}
}
}
return $result;
}
return TRUE;
}
}
GUI
When it comes to GUI there are several approaches/patterns. The most common, I think, for email related apps is to have a number of rows of expressions that are ANDed and a [+] to add more conditions:
Row 1: [select: subject] [select:contains] [input:"Order Confirmation"]
When it comes to the from we need to express OR. This is hard to do with just rows. This is where the concept of a Prerequisite or Condition group becomes handy. You simply add a new row which is a group and let the user to choose to use AND or OR.
The outer group is an AND group.
So the GUI elements are fairly easy to transform into code and vice versa - especially with the KeyValuePrerequisite impl. of Prerequisite.
Hope this helps or at least sparked some ideas to solve your problem.
I've got a "make-do" page authenticator which defines what usergroups are allowed to access that page, however, some of my scripts allow the user to pass if that page is, say, his user edit page but not touch any other users edit page. For that, I disabled access to the usergroups except if you're an admin or the user edit page you are currently on is your own.
I tried to create a function to do this, but the allowOnly usergroups function deals out the punishment without checking to see if the other function is defined elsewhere on the page.
Here's the "make-do" functions and an example of how I'd like them to work:
public function allowOnly($officer, $administrator, $superuser)
{
$authority = 0;
if ($officer == true && $this->session->isOfficer()) {
$authority++;
}
elseif ($administrator == true & $this->session->isAdmin()) {
$authority++;
}
elseif ($superuser == true & $this->session->isSuperuser()) {
$authority++;
}
if ($authority != 0) {
return true;
}
else {
header("Location: ../incorrectRights.php");
exit;
}
}
function allowCurrentUser()
{
global $authority;
$authority++;
}
This changes the users location if they're not any of the allowed usergroups, but since that code is executed before "allowCurrentUser", it changes the location before the function gets the chance to allow the user through.
I'd like it to work like this:
<?php
include("functions.php");
$functions->allowOnly(false, false, true);
if($session->username == $allowedUserName) {
$functions->allowCurrentUser();
}
I'm sorry if I'm not descriptive enough, or my code lacks efficiency, heck, even if I've missed a built-in php function which does this for me!
you should check out PHP's function_exists(), this will tell you wether or not the function already exist.
you have some error in your code too.
$administrator == true & $this->session->isAdmin()
should be
$administrator == true && $this->session->isAdmin()
as you have used only single & whereas it should be &&
and also change
$superuser == true & $this->session->isSuperuser()
to
$superuser == true && $this->session->isSuperuser()
after reading your code, i realized you are using $authority variable to hold the value and to check wether to authorize user or not. and plus you are using global. i would never have done that way, instead i would declare $authority as class property below is the example of how you could do it.
class functions
{
//declare class propert and set default value to 0
protected $_authority = 0;
public function allowOnly($officer, $administrator, $superuser)
{
if ($officer == true && $this->session->isOfficer()) {
$this->_authority++;
}
elseif ($administrator == true && $this->session->isAdmin()) {
$this->_authority++;
}
elseif ($superuser == true && $this->session->isSuperuser()) {
$this->_authority++;
}
if ($this->_authority != 0) {
return true;
}
else {
header("Location: ../incorrectRights.php");
exit;
}
}
public function allowCurrentUser()
{
$this->_authority++;
return $this->_authority;
}
}
UPDATE:
instead of redirecting the page why not return false and redirect during function call, you can do it this way.
class functions
{
//declare class propert and set default value to 0
protected $_authority = 0;
public function allowOnly($officer, $administrator, $superuser)
{
if ($officer == true && $this->session->isOfficer()) {
$this->_authority++;
}
elseif ($administrator == true && $this->session->isAdmin()) {
$this->_authority++;
}
elseif ($superuser == true && $this->session->isSuperuser()) {
$this->_authority++;
}
return ($this->_authority != 0) ? true : false;
}
public function allowCurrentUser()
{
$this->_authority++;
return $this->_authority;
}
}
and while in function call.
include("functions.php");
if($functions->allowOnly(false, false, true)) {
//person is allowed access
}
//else allow current user
elseif($session->username == $allowedUserName) {
$functions->allowCurrentUser();
}
else {
//redirect here
header("Location: ../incorrectRights.php");
exit;
}
I'm not completely certain if this is the answer you are looking for based on the title but this is what I get the impression you are asking for.
Assuming what happens is that your check against allowOnly() takes the user to the "../incorrectRights.php"-page before you've checked if the user logged in is the same as the page looked at, what you need to do is put the check inside the allowOnly function or at least before you do the check for $authority != 0.
Here's a quick example of how you could solve this:
public function allowOnly($officer, $administrator, $superuser)
{
$authority = 0;
if ($officer == true && $this->session->isOfficer()) {
$authority++;
}
elseif ($administrator == true && $this->session->isAdmin()) {
$authority++;
}
elseif ($superuser == true && $this->session->isSuperuser()) {
$authority++;
}
if(function_exists('allowCurrentUser')){
if (allowCurrentUser()) {
return true;
}
}
if ($authority != 0) {
return true;
}
else {
header("Location: ../incorrectRights.php");
exit;
}
}
function allowCurrentUser()
{
if($session->username == $allowedUserName){
return true;
}
else {
return false;
}
}
Then your useage would result in something more like
<?php
include("functions.php");
$functions->allowOnly(false, false, true);
?>
As you can see I also threw in the function_exists('functionnamehere') call that seems to be requested in the question title, since we actually declare the function and therefore know it exists you could also just do this:
if ($authority != 0 || allowCurrentUser()) {
return true;
}