PHP MYSQL/PDO mocking interaction/data - php

Recently getting back up-to-speed with unit testing. Been scouring the net for a good mock PDO SQL class for interactions/data but can't seem to one that doesn't require you to parse what the raw sql is into the mock obj during the test script.
This might be okay for some, but IMO it takes too much away from the test script (I'm trying to minimize complications to help sell the concept to my team at work)
Ideally I'd expect the test to look more like this:
public static function setUpBeforeClass()
{
// Use PDOMock version in replace of all PDO calls
PDOMock::initMockMode();
// Potentially drive data provider from a file
$data = [
[
'id' => 1,
'total' => 1,
],
[
'id' => 2,
'total' => 1,
],
[
'id' => 3,
'total' => 10,
],
];
PDOMock::setTableData('db.example_table', $data);
}
public function testSqlMock()
{
// Presumming the sumTableValues() method runs a simple sum query over the db.example_table using the regular \PDO class
$total = TestClass::sumTableValues();
$this->assertEquals(12, $total); // assertion passes due to PDOMock class using set data over live mysql data
}
It doesn't really need to have the fancy PDOMock::initMockMode() logic either as I can compromise by adding a setMockMode() in my sqlclass to just use the mocked version instead of \PDO
Hope this makes sense; any ideas/suggestions are greatly appreciated!

Related

PhpUnit and Laravel 5.4 how to mock Session data during a test

I'm testing a class in laravel 5.4 with phpunit that uses the session to get data. Retrieving the session data works when accessing it directly when the app is running aka "session('consumer')" returns a value, however when i try to test a function that uses the session, I get the below error:
ReflectionException: Class session does not exist
Can someone please shed some light on how to accomplish setting session data during a test.
I have tried using:
$this->session()->put([$array_value]) but get an error "class session does not exist on class_im_testing"
Thanks in advance for your help!
public function test_get_user()
{
$mockUser = [
'id' => 'cf442564-d076-4198-beb5-edef5aa51a69',
'name' => 'John Doe',
'fname' => 'John',
'lname' => 'Doe',
];
session->put('consumer', [
'id' => 'cf442564-d076-4198-beb5-edef5aa51a69',
'name' => 'John Doe',
'fname' => 'John',
'lname' => 'Doe',
]);
$user = $this->repo->getUser();
$this->assertEqual($user, $mockUser);
}
public function getUser()
{
$user = new User(session('consumer'));
return $user;
}
Laravel offers a lot of methods to help with testing but in order to make use of them you need to ensure you are using the correct class.
If you're using the default boilerplate you get a TestCase class. This is the class you need to extend in order to get method such as $this->withSession.
This is because the test case extends the Framework TestCase class which in turn includes many traits, among them is the the trait InteractsWithSession which is the trait which actually offers the method withSession.
In addition the Laravel TestCase also extends the PhpUnit test case so you still have access to all PhpUnit assertions.

How to prevent SQL Injection in Laravel 5.4

I am using Laravel 5.4. I have a form where I take some inputs from user. The form variables are directly inserted into database. I want to make sure the sure does not enter anything that could harm the database. I have heard of something SQL Injection but I don't know much about it.
This is my function.
public function insert_data(Request $request)
{
$company_details_data = ['job_id' => $maxID,
'company_id' => $company_id,
'job_title' => ucwords($request>input('job_title')),
'vacancy_no' => $request->input('vacancy_no'),
'category_id' => $request->input('category_id'),
'job_type_id' => $request->input('job_type_id'),
'city_id' => $request->input('city_id'),
'travel_required' => $request->input('travel_required'),
'other_locations' => ucwords($request->input('other_locations')),
'no_vacancy' => $request->input('no_vacancy'),
'job_salary' => $request->input('job_salary'),
'date_expiry' => $request->input('date_expiry'),
'job_details' => $request->input('job_details'),
'date_posted' => date('Y-m-d'),
'qualification_required' => $request->input('qualification_required'),
'experience_required' => $request->input('experience_required'),
'skills_required' => $request->input('skills_required'),
'apply_guidance' => $request->input('apply_guidance'),
'duty_responsibilities' => $request->input('duty_responsibilities')
];
General_model::createrecord($company_details_data,'job_details');
}
This is the createrecord() function in my model:
public static function createrecord($data,$tbl)
{
return DB::table($tbl)->insert($data);
}
I want to use htmlspecialchars here but I am using a rich texteditor in my form. If I use htmlspecialchars it will also change the unharmful tags like ,< p >, < br >,etc. Please Help
Without being able to see the methods on your model that take this data and actually push them into the DB its difficult to tell.
Ideally you'd want to sanitize your data prior to handing it to any class. Also you'd want to make sure your models if not already using an existing ORM were using something akin to PDO for your database interactions.
See the answers to the following question as to what sanitizing a request for the DB actually entails.
EDIT:
As others have pointed out, it most likely makes more sense here to use an ORM like Eloquent in laravel that handles a lot of this for you.
What's the best method for sanitizing user input with PHP?

Cakephp need session var in model

I give. Been searching and trying different stuff for hours.
Using Cakephp 2.3.5.
I'll get straight to it.
I want to use a session variable in my Category model, but it doesn't like it when I try any of the following...
$this->Session->read('market_id')
CakeSession::read('market_id')
SessionHelper::read('market_id')
Here is the model snippet where I'm trying to use it...
public $hasAndBelongsToMany = array(
'Vendor' => array(
'className' => 'Vendor',
'joinTable' => 'categories_vendors',
'foreignKey' => 'category_id',
'associationForeignKey' => 'vendor_id',
'unique' => 'keepExisting',
'conditions' => array( 'market_id' => ???? )
)
);
I'm stuck like a wheelbarrow in the mud. I've read countless opinions of why I shouldn't use session data in the model, but this makes perfect sense to me since it will never be called without this value set, and it should never return anything other than the vendors with that market_id. But that value does change.
I'm completely guilty of doing everything I can to avoid messing with my models. The whole skinny controller idea... yea... nice thought, but I just haven't figured it out yet. And so it goes. The first time I try to modify a model... I can't figure out how.
I've read countless opinions of why I shouldn't use session data in the model
That's correct. It will cause tight coupling as well and make it harder to test. And it's not only valid for models but everything. Don't create tight coupled code.
It is better to pass data and objects around. For example:
// Model Method
public function getSomething($someSessionValue) { /*...*/ }
// Controller
$this->SomeModel->getSomething($this->Session->read('something'));
If you need your data in a lot methods you can set it:
public function setSomeModelProperty($value) {
$this->_someProperty = value; // _ because it should be protected, the _ is the convention for that in CakePHP
}
However, I personally would very like go for passing the data to each method. But it depends on the whole scenario.
And you can't do this any way because it will cause a syntax error. You can't use variables or properties in the property declaration.
'conditions' => array( 'market_id' => ???? )
So bind it later by a method like
public function bindVendors($marketId) {
$this->bindModel(/*...*/);
}
when needed.
Or even better, simply use the conditions only when needed and declare them in your find options:
[
'contain' => [
'Vendor' => [
'conditions' => /* conditions here */
]
]
]

Sandboxing Mongo->execute(MongoCode) in PHP to prevent any DB interaction

As a feature in the software I'm writing, I'm allowing myself to create calculators written in JS to compute the fees to be applied to a specific set of data, using said data as a reference. Since I'm using Mongo, I can run this safely server-side, and the browser can just call a php page and get the response. The function will be written from an administration control panel and saved to the database. I of course won't be doing any db interactions from inside that function, but executing mongocode is done within the database, so mongocode by nature can do db.foo
Just to protect myself and anyone else who might end up writing calculators, I've set db = null; in $context being passed to new MongoCode()
It looks a bit like this:
$sample = [
'estimatedvalue' => 200,
'estimatedcost' => 400,
'contractor' => false,
'db' => null,
];
$fees = [
'_id' => new MongoId(),
'name' => 'Friendly name!',
'code' => new MongoCode('function(){return (contractor ? estimatedCost : estimatedValue)*0.01; /* If a contractor is doing the work, base fee on cost. */}', $sample),
];
$a = $this->siteDB->execute($fees['code']);
if(isset($a['errno'])){
echo $a['errmsg'];
}else{
var_dump($a['retval']);
}
Fortunately, that works, and if I was to inject that into all context, there would be no db. commands runnable. I don't want to create a point where NoSQL injection can happen!
An example of something that this prevents is:
'code' => new MongoCode('function(){db.foo.remove();}', $sample),
// Since db is now null, the above won't work
My concern: Are there any other variables that exist in this MongoCode Execute environment that could be potentially harmful to leave in a user-editable function? I couldn't find any documentation on what else is accessible through mongocode functions. If db is it, then I'm all set!
This is not safe, and I don't think you can have a user-editable JS function that is. For example, this requires no variables and shuts down your server:
> db.eval("(new Mongo('localhost:27017')).getDB('admin').shutdownServer()")
They can insert data, drop databases, connect to other servers in your system, and generally wreck havoc.
If you are trying to allow a user-editable compute function in JavaScript, use a separate JS engine, pull the values from MongoDB, and pass the values + user-defined function to the totally separate JS engine.

Rest Interface for MySQL DB with ACL

99% of what REST API's do is serve as a controlled interface between client and DB, and yet I can't for the life of me find any libraries that do just that.
All libraries focus on providing a REST interface to the developer, who then sets up the communication with the database. It seems like a no-brainer to me to create a library that already interfaces with the database, and all the developer needs to do is define some ACL rules and plug in some logic here or there.
So, before I continue and put my thoughts into actions by actually creating this sort of library, may I just ask anyone with knowledge on the subject; has anyone implemented anything like this yet? Will I be re-inventing the wheel?
I'm talking strictly about a PHP based solutions by the way, I have nothing against other languages, PHP is simply my cup of tea. But for that matter, I haven't found any implementations in other languages either.
And in case my explanation doesn't make it very clear, this is essentially what I'd want:
<?php
class post_controller extends controller {
protected static $config = array(
'select' => true,
'insert' => true,
'update' => true,
'delete' => false,
'fields' => array(
'id' => array(
'select' => true,
'update' => false
),
'name' => array(
'select' => true,
'update' => true
),
'content' => array(
'select' => true,
'update' => true
)
)
);
/**
* GET, POST, DELETE are implemented already by the parent controller
* Just overriding PUT to modify the content entry
*/
function put($data) {
$data->content = htmlentities($data);
return parent::put($data);
}
}
?>
Thanks in advance for anyone giving their input and apologies if this is not a proper Stackoverflow question.
Edit:
To clarify, this type of service would be for specific use-cases, I don't imagine it to be a type of thing that anyone can use for any type of web service.
I have built a similar system for SOAP and must say it's very easy to do so. I haven't seen any prebuilt libraries that would help you do it (and I doubt they exist - see next paragraph), but it shouldn't take you more than a few hours to build your own solution (a day max - with testing and documentation writing included).
It is however a whole another question if you really want to do that. REST can be (mis)used for this purpose, but it is meant for manipulating resources. Records in a database only rarely have a one-to-one mapping with resources. If they do in your case (as they did in mine) then feel free to do it, otherwise it would be nicer to provide a proper REST API. Why expose your internal DB structure to the world? YMMV, of course.

Categories