Inappropriate coding practices - Php
Need
Enforce proper encapsulation in coding practices
Context
- Usage of PHP for server-side scripting and web development
- Usage of PHP for server-side scripting and web development
Description
Insecure Code Example
class User {
public $name;
public $email;
public $password;
}
In the above PHP code, a class named `User` is defined with three public fields: `name`, `email`, and `password`. The problem with this code is that it does not adhere to the principle of encapsulation. Encapsulation is one of the fundamental principles of object-oriented programming. It refers to the bundling of data, and the methods that operate on that data, into a single unit called a class. In PHP, the visibility of a property, a method, or a constant can be defined by prefixing the declaration with the keywords public, protected, or private. Public declared items can be accessed everywhere. Protected limits access to inherited and parent classes, and private limits visibility only to the class that defines the item. By declaring the fields as public, we are allowing these variables to be accessed and modified directly from outside the class. This can lead to unwanted side-effects, as the class cannot control what values are being assigned to its fields. For example, the `password` field should be private and should not be directly accessible. It should only be modified through a method in the `User` class that can ensure the password meets certain requirements (e.g., minimum length, contains special characters, etc.). If the `password` field is public, any code that uses the `User` class could directly modify the `password`, potentially setting it to a value that does not meet the required standards or even worse, leaving it blank. The same applies to the `name` and `email` fields. There might be certain restrictions on what these fields can contain (e.g., `name` should not contain numeric or special characters, `email` should be in a valid format, etc.), and by making these fields public, we are not able to enforce these rules. This inappropriate coding practice leads to a violation of data integrity and security, which is a major concern in any backend application.
Steps
- Change the access modifier of the fields from public to private or protected. This will ensure that these fields cannot be accessed directly from outside the class.
- Create getter and setter methods for each field. This will allow controlled access to the fields. The getter method will return the value of the field, and the setter method will allow you to change the value of the field.
- In the setter methods, add validation logic to ensure that only valid data is set to the fields. This can help prevent issues such as setting a null value to a field that should always have a value.
- In the getter methods, you can also add logic to control how the data is returned. For example, you might want to return a copy of an object rather than the object itself to prevent the caller from modifying the original object.
- Ensure that all code that previously accessed the fields directly is updated to use the new getter and setter methods.
Secure Code Example
class User {
private $name;
private $email;
private $password;
public function getName() {
return $this->name;
}
public function setName($name) {
if (!is_string($name)) {
throw new InvalidArgumentException('Name must be a string');
}
$this->name = $name;
}
public function getEmail() {
return $this->email;
}
public function setEmail($email) {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('Invalid email format');
}
$this->email = $email;
}
public function getPassword() {
return $this->password;
}
public function setPassword($password) {
if (strlen($password) < 8) {
throw new InvalidArgumentException('Password must be at least 8 characters long');
}
$this->password = password_hash($password, PASSWORD_DEFAULT);
}
}
The code above is a refactored version of the `User` class. The fields `$name`, `$email`, and `$password` have been changed from `public` to `private` to respect the encapsulation principle. This means that these fields can no longer be accessed directly from outside the class. Getter and setter methods have been added for each field. The getter methods (`getName()`, `getEmail()`, and `getPassword()`) return the value of the respective field. The setter methods (`setName($name)`, `setEmail($email)`, and `setPassword($password)`) allow the value of the respective field to be changed. In the setter methods, validation logic has been added to ensure that only valid data is set to the fields. For example, the `setName($name)` method checks that `$name` is a string, the `setEmail($email)` method checks that `$email` is a valid email format, and the `setPassword($password)` method checks that `$password` is at least 8 characters long and hashes the password before storing it. This refactoring ensures that the `User` class is more secure and respects the encapsulation principle. All code that previously accessed the fields directly should be updated to use these new getter and setter methods.
References
Last updated
2023/09/18