In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article introduces the knowledge of "how to prevent injection of php framework". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!
Take reading, for example, what does Yii do behind the scenes if you visit $Component- > property1? Here, look at yii\ base\ Component::__get ().
Public function _ _ get ($name)
{
$getter = 'get'. $name
If (method_exists ($this, $getter)) {
Return $this- > $getter ()
} else {
/ / Note the content of this else branch, which is exactly the same as yii\ base\ Object::__get ().
/ / differences
$this- > ensureBehaviors ()
Foreach ($this- > _ behaviors as $behavior) {
If ($behavior- > canGetProperty ($name)) {
/ / the attribute must be public in the behavior. Otherwise, it is impossible to access it through the following form.
Return $behavior- > $name
}
}
}
If (method_exists ($this, 'set'. $name)) {
Throw new InvalidCallException ('Getting write-only property:'.
Get_class ($this). ':'. $name)
} else {
Throw new UnknownPropertyException ('Getting unknown property:'.
Get_class ($this). ':'. $name)
}
}
Focus on the differences between yii\ base\ Compoent::__get () and yii\ base\ Object::__get (). That is, for the handling after the getter function is not defined, yii\ base\ Object directly throws an exception, telling you that the property you want to access does not exist. However, yii\ base\ Component needs to see if it is an attribute of the injected behavior after there is no getter:
First, $this- > ensureBehaviors () is called. This method has been discussed earlier, mainly to ensure that the behavior is bound.
After ensuring that the behavior is bound, start traversing $this- > _ behaviors. Yii saves all the bound behavior of the class in the yii\ base\ Compoent::$_behaviors [] array.
Finally, the canGetProperty () of the behavior is used to determine whether the property is readable for the bound behavior, and if so, the property $behavior- > name of the behavior is returned. Finish reading the attribute. As for canGetProperty (), it has been briefly discussed in the: ref::property section, and there will be a targeted introduction later.
For setter, the code is similar, so it doesn't take up space here.
Injection of method
Similar to the injection of attributes through the _ _ get () _ set () magic method, Yii uses the _ _ call () magic method to inject methods in the behavior:
Public function _ _ call ($name, $params)
{
$this- > ensureBehaviors ()
Foreach ($this- > _ behaviors as $object) {
If ($object- > hasMethod ($name)) {
Return call_user_func_array ([$object, $name], $params)
}
}
Throw new UnknownMethodException ('Calling unknown method:'.
Get_class ($this). ": $name ()")
}
As you can see from the above code, Yii first calls $this- > ensureBehaviors () to ensure that the behavior is bound.
Then, also iterate through the yii\ base\ Component::$_behaviros [] array. Determine whether the method exists by the hasMethod () method. If the method to be called exists in the bound behavior, it is called using PHP's call_user_func_array (). As for the hasMethod () method, we'll talk about it later.
Access control of injection properties and methods
Earlier, we gave a specific example of whether the members of public, private and protected in the behavior are accessible in the bound class. Here we analyze the reason at the code level.
In the above content, we know that a property is inaccessible, depending on the canGetProperty () and canSetProperty () of the behavior. A method can not be called, depending on the hasMethod () of the behavior. Since yii\ base\ Behavior inherits from our old friend yii\ base\ Object, the code for the three judgments mentioned above is actually in Object. Let's look at it one by one:
Public function canGetProperty ($name, $checkVars = true)
{
Return method_exists ($this, 'get'. $name) | | $checkVars & &
Property_exists ($this, $name)
}
Public function canSetProperty ($name, $checkVars = true)
{
Return method_exists ($this, 'set'. $name) | | $checkVars & &
Property_exists ($this, $name)
}
Public function hasMethod ($name)
{
Return method_exists ($this, $name)
}
These three methods are really not complicated. In this regard, we can draw the following conclusions:
When reading (writing) an attribute to a Component-bound behavior, it can be accessed if the behavior defines a getter (setter) for the property. Or, if the behavior does have the member variable, it can pass the above judgment, in which case, the member variable can be public, private, protected. But in the end, only the member variables of public can be accessed correctly. The reason has already been explained when talking about the principle of injection above.
When a method of a Component-bound behavior is called, the above judgment can be passed if the behavior has already defined the method. At this point, this method can be public, private, protected. But in the end, only the method of public can be called correctly. If you understand the reason of the previous paragraph, then you will understand it here.
Dependency injection container
A dependency injection (Dependency Injection,DI) container is an object that knows how to initialize and configure an object and all the objects it depends on. Martin's article has explained why DI containers are useful. Here we focus on how to use the DI container provided by Yii.
Dependency injection
Yii provides DI container features through the yii\ di\ Container class. It supports the following types of dependency injection:
1. Construction method injection
2.Setter and attribute injection
3.PHP callback injection.
4. Construction method injection
With the help of parameter type hints, the DI container implements constructor injection. When the container is used to create a new object, the type hint tells it which class or interface to rely on. The container attempts to get an instance of the class or interface it depends on and then inject it into the new object through the constructor. For example:
Class Foo
{
Public function _ _ construct (Bar $bar)
{
}
}
$foo = $container- > get ('Foo')
/ / the above code is equivalent to:
$bar = new Bar
$foo = new Foo ($bar)
Setter and attribute injection
Setter and attribute injection are supported through configuration. When registering a dependency or creating a new object, you can provide a configuration that is provided to the container to inject the dependency through the corresponding Setter or attribute. For example:
Use yii\ base\ Object
Class Foo extends Object
{
Public $bar
Private $_ qux
Public function getQux ()
{
Return $this- > _ qux
}
Public function setQux (Qux $qux)
{
$this- > _ qux = $qux
}
}
$container- > get ('Foo', [], [
'bar' = > $container- > get (' Bar')
'qux' = > $container- > get (' Qux')
])
PHP callback injection
In this case, the container creates a new instance of the class using a registered PHP callback. The callback is responsible for resolving the dependency and injecting it properly into the newly created object. For example:
$container- > set ('Foo', function () {
Return new Foo (new Bar)
});
$foo = $container- > get ('Foo')
Registration dependency
You can register dependencies with yii\ di\ Container::set (). Registration uses a dependency name and a dependency definition. The dependency name can be a class name, an interface name, or an alias. The definition of a dependency can be a class name, a configuration array, or a PHP callback.
$container = new\ yii\ di\ Container
/ / register a dependency with the same name, which can be omitted.
$container- > set ('yii\ db\ Connection')
/ / register an interface
/ / when a class depends on this interface, the corresponding class is initialized as a dependent object.
$container- > set ('yii\ mail\ MailInterface',' yii\ swiftmailer\ Mailer')
/ / register an alias.
/ / you can create a Connection instance using $container- > get ('foo')
$container- > set ('foo',' yii\ db\ Connection')
/ / register a class through configuration
/ / when initialized through get (), the configuration will be used.
$container- > set ('yii\ db\ Connection', [
'dsn' = >' mysql:host=127.0.0.1;dbname=demo'
'username' = >' root'
'password' = >''
'charset' = >' utf8'
])
/ / register an alias through the configuration of the class
/ / in this case, you need to specify this class through a "class" element
$container- > set ('db', [
'class' = > 'yii\ db\ Connection'
'dsn' = >' mysql:host=127.0.0.1;dbname=demo'
'username' = >' root'
'password' = >''
'charset' = >' utf8'
])
/ / Register a PHP callback
/ / every time $container- > get ('db') is called, the callback function is executed.
$container- > set ('db', function ($container, $params, $config) {
Return new\ yii\ db\ Connection ($config)
});
/ / register a component instance
/ / $container- > get ('pageCache') returns the same instance every time it is called.
$container- > set ('pageCache', new FileCache)
Tip: if the dependency name and the definition of the dependency are the same, you do not need to register the dependency through the DI container.
A dependency registered with set () produces a new instance each time it is used. You can register a singleton dependency using yii\ di\ Container::setSingleton ():
$container- > setSingleton ('yii\ db\ Connection', [
'dsn' = >' mysql:host=127.0.0.1;dbname=demo'
'username' = >' root'
'password' = >''
'charset' = >' utf8'
])
Resolve dependencies
After registering the dependency, you can use the DI container to create a new object. The container automatically resolves the dependency, instantiates the dependency and injects the newly created object. The resolution of dependencies is recursive, and if there are other dependencies in a dependency, these dependencies will be resolved automatically.
You can create a new object using yii\ di\ Container::get (). This method receives a dependency name, which can be a class name, an interface name, or an alias. The dependency name may be registered through set () or setSingleton (). You can optionally provide a list of constructor parameters for a class and a configuration to configure the newly created object. For example:
/ / "db" is an alias defined earlier
$db = $container- > get ('db')
/ / equivalent to: $engine = new\ app\ components\ SearchEngine ($apiKey, ['type' = > 1])
$engine = $container- > get ('app\ components\ SearchEngine', [$apiKey], [' type' = > 1])
Behind the code, the DI container does a lot more work than creating an object. The container first examines the constructor of the class, finds the name of the dependent class or interface, and then automatically recursively resolves these dependencies.
The following code shows a more complex example. The UserLister class relies on an object that implements the UserFinderInterface interface; the UserFinder class implements this interface and relies on a Connection object. All of these dependencies are defined through the type hint of the class constructor parameter. Through the registration of attribute dependencies, the DI container can automatically resolve these dependencies and create a new UserLister instance through a simple get ('userLister') call.
Namespace app\ models
Use yii\ base\ Object
Use yii\ db\ Connection
Use yii\ di\ Container
Interface UserFinderInterface
{
Function findUser ()
}
Class UserFinder extends Object implements UserFinderInterface
{
Public $db
Public function _ _ construct (Connection $db, $config = [])
{
$this- > db = $db
Parent::__construct ($config)
}
Public function findUser ()
{
}
}
Class UserLister extends Object
{
Public $finder
Public function _ _ construct (UserFinderInterface $finder, $config = [])
{
$this- > finder = $finder
Parent::__construct ($config)
}
}
$container = new Container
$container- > set ('yii\ db\ Connection', [
'dsn' = > '...'
])
$container- > set ('app\ models\ UserFinderInterface', [
'class' = > 'app\ models\ UserFinder'
])
$container- > set ('userLister',' app\ models\ UserLister')
$lister = $container- > get ('userLister')
/ / equivalent to:
$db = new\ yii\ db\ Connection (['dsn' = >'...'])
$finder = new UserFinder ($db)
$lister = new UserLister ($finder)
Application in practice
When the Yii.php file is introduced into the application's entry script, Yii creates a DI container. This DI container can be accessed through Yii::$container. When Yii::createObject () is called, this method actually calls the container's yii\ di\ Container::get () method to create a new object. As mentioned above, the DI container automatically resolves the dependency (if any) and injects it into the newly created object. Because Yii uses Yii::createObject () to create new objects in most of its core code, you can customize these objects globally through Yii::$container.
For example, you can globally customize the default number of paging buttons in yii\ widgets\ LinkPager:
\ Yii::$container- > set ('yii\ widgets\ LinkPager', [' maxButtonCount' = > 5])
So if you use the widget in a view with the following code, its maxButtonCount property will be initialized to 5 instead of the default value of 10 defined in the class.
Echo\ yii\ widgets\ LinkPager::widget ()
However, you can still override the values set through the DI container:
Echo\ yii\ widgets\ LinkPager::widget (['maxButtonCount' = > 20])
Another example is to borrow the benefits of automatic constructor injection in the DI container. Suppose your controller class depends on some other object, such as a hotel reservation service. You can declare the dependency through a constructor parameter, and then ask the DI container to automatically resolve the dependency for you.
Namespace app\ controllers
Use yii\ web\ Controller
Use app\ components\ BookingInterface
Class HotelController extends Controller
{
Protected $bookingService
Public function _ construct ($id, $module, BookingInterface $bookingService, $config = [])
{
$this- > bookingService = $bookingService
Parent::__construct ($id, $module, $config)
}
}
If you access the controller from a browser, you will see an error message reminding you that BookingInterface cannot be instantiated. This is because you need to tell the DI container how to handle this dependency.
\ Yii::$container- > set ('app\ components\ BookingInterface',' app\ components\ BookingService')
Now if you visit the controller again, an instance of app\ components\ BookingService will be created and injected into the controller's constructor as the third parameter.
When to register for dependencies
Because dependencies need to be addressed when creating new objects, their registration should be completed as soon as possible. The following are recommended practices:
If you are an application developer, you can register dependencies in the entry script of the application or in the script introduced by the entry script.
If you are a developer of redistributable extensions, you can register dependencies with the extension's boot class.
This is the end of the content of "how to prevent injection of php Framework". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.