특정 사용자의 액세스를 제한해야 하는 웹페이지의 경우 인증 및 권한 부여를 사용해야 합니다. 검증은 그 사람이 주장하는 사람이 맞는지 확인하는 것을 의미합니다. 여기에는 일반적으로 사용자 이름과 비밀번호가 필요하지만 스마트 카드, 지문 등과 같이 자신을 식별하는 다른 수단도 포함됩니다. 권한 부여는 인증된 사용자가 특정 리소스를 작동할 수 있는지 여부를 확인하는 것입니다. 이는 일반적으로 사용자가 리소스에 대한 액세스 권한이 있는 역할에 속하는지 여부를 쿼리하여 결정됩니다.
Yii에는 사용하기 쉽고 특별한 요구 사항에 맞게 사용자 정의할 수 있는 인증/권한 부여(auth) 프레임워크가 내장되어 있습니다.
Yii 인증 프레임워크의 핵심은 IWebUser 인터페이스를 구현하는 개체인 사전 정의된 사용자 애플리케이션 구성 요소입니다. 이 사용자 구성 요소는 현재 사용자의 지속적인 인증 정보를 나타냅니다. Yii::app()->user
을 통해 어디서나 액세스할 수 있습니다.
이 사용자 구성 요소를 사용하면 CWebUser::isGuest를 통해 사용자가 로그인했는지 확인할 수 있습니다. 이 사용자가 CWebUser::checkAccess를 통해 로그인할 수 있는지 확인할 수 있습니다. 특정 작업을 수행하면 이 사용자의 고유 식별자와 기타 영구 신원 정보를 얻을 수도 있습니다.
1. ID 클래스 정의
사용자를 확인하기 위해 검증 로직을 사용하여 ID 클래스를 정의합니다. 이 ID 클래스는 IUserIdentity 인터페이스를 구현합니다.
다른 클래스는 다른 인증 방법(예: OpenID, LDAP)을 구현할 수 있습니다. 사용자 이름과 비밀번호에 대한 인증 방법인 CUserIdentity를 상속하는 것이 가장 좋습니다.
ID 클래스를 정의하는 주요 작업은 IUserIdentity::authenticate 메서드를 구현하는 것입니다. 사용자 세션에서 ID 클래스는 필요에 따라 다른 ID 정보를 정의해야 할 수도 있습니다
애플리케이션 예제
다음 예제에서는 Active Record를 사용하여 사용자 이름, 비밀번호 및 데이터베이스 테이블이 일치합니까? 확인 프로세스 중에 얻은 getId
변수를 반환하도록 _id
함수를 다시 작성합니다(기본 구현에서는 사용자 이름을 반환합니다). 검증 과정에서 획득한 title
정보를 상태로 저장하기 위해 CBaseUserIdentity::setState 함수도 사용했습니다.
데이터베이스를 사용하여 자격 증명을 검증하는
authenticate()
구현.CUserIdentity::getId()
메서드를 재정의하여 속성은 기본 구현이 사용자 이름을 ID로 반환하기 때문입니다._id
(CBaseUserIdentity::setState) 메서드를 사용하여 후속 요청 시 쉽게 검색할 수 있는 다른 정보를 저장하는 방법을 보여줍니다. .
setState()
class UserIdentity extends CUserIdentity { private $_id; public function authenticate() { $record=User::model()->findByAttributes(array('username'=>$this->username)); if($record===null) $this->errorCode=self::ERROR_USERNAME_INVALID; else if($record->password!==md5($this->password)) $this->errorCode=self::ERROR_PASSWORD_INVALID; else { $this->_id=$record->id; $this->setState('title', $record->title); $this->errorCode=self::ERROR_NONE; } return !$this->errorCode; } public function getId() { return $this->_id; } }
정보를 얻으려면 title
을 사용할 수 있습니다(이 기능은 버전 1.0.3에서 도입되었습니다. 이전 버전에서는 Yii::app()->user->title
을 사용해야 했습니다). Yii::app()->user->getState('title')
2. 로그인 및 로그아웃 ID 클래스와 사용자 구성요소를 사용하여 쉽게 로그인 및 로그아웃을 구현할 수 있습니다.팁: 기본적으로 CWebUser는 세션을 사용하여 사용자 ID 정보를 저장합니다. 쿠키 기반 로그인이 허용되면(CWebUser::allowAutoLogin을 true로 설정) 사용자 신원 정보가 쿠키에 저장됩니다. 비밀번호 등 민감한 정보는 저장하지 마세요.
// 使用提供的用户名和密码登录用户 $identity=new UserIdentity($username,$password); if($identity->authenticate()) Yii::app()->user->login($identity); else echo $identity->errorMessage; ...... // 注销当前用户 Yii::app()->user->logout();
및 $username
값)을 생성자에 전달합니다. 그런 다음 $password
메서드를 호출하면 됩니다. 성공하면 ID 정보를 CWebUser::login 메서드에 전달합니다. 후속 요청 시 검색을 위해 신원 정보를 영구 저장소(기본적으로 PHP 세션)에 저장합니다. 인증이 실패하면 authenticate()
속성에서 실패 이유에 대한 자세한 내용을 조사할 수 있습니다.errorMessage
Whether or not a user has been authenticated can easily be checked throughout the application by usingYii::app()->user->isGuest
. If using persistent storage like session (the default) and/or a cookie (discussed below) to store the identity information, the user can remain logged in upon subsequent requests. In this case, we don't need to use the UserIdentity class and the entire login process upon each request. Rather CWebUser will automatically take care of loading the identity information from this persistent storage and will use it to determine whether Yii::app()->user->isGuest
returns true or false.
基于Cookie 的登录
缺省情况下,用户将根据session configuration完成一序列inactivity动作后注销。设置用户部件的allowAutoLogin属性为true和在CWebUser::login方法中设置一个持续时间参数来改变这个行为。即使用户关闭浏览器,此用户将保留用户登陆状态时间为被设置的持续时间之久。前提是用户的浏览器接受cookies。
// 保留用户登陆状态时间7天 // 确保用户部件的allowAutoLogin被设置为true。 Yii::app()->user->login($identity,3600*24*7);
As we mentioned above, when cookie-based login is enabled, the states stored viaCBaseUserIdentity::setState will be saved in the cookie as well. The next time when the user is logged in, these states will be read from the cookie and made accessible via Yii::app()->user
.
Although Yii has measures to prevent the state cookie from being tampered on the client side, we strongly suggest that security sensitive information be not stored as states. Instead, these information should be restored on the server side by reading from some persistent storage on the server side (e.g. database).
In addition, for any serious Web applications, we recommend using the following strategy to enhance the security of cookie-based login.
When a user successfully logs in by filling out a login form, we generate and store a random key in both the cookie state and in persistent storage on server side (e.g. database).
Upon a subsequent request, when the user authentication is being done via the cookie information, we compare the two copies of this random key and ensure a match before logging in the user.
If the user logs in via the login form again, the key needs to be re-generated.
By using the above strategy, we eliminate the possibility that a user may re-use an old state cookie which may contain outdated state information.
To implement the above strategy, we need to override the following two methods:
CUserIdentity::authenticate(): this is where the real authentication is performed. If the user is authenticated, we should re-generate a new random key, and store it in the database as well as in the identity states via CBaseUserIdentity::setState.
CWebUser::beforeLogin(): this is called when a user is being logged in. We should check if the key obtained from the state cookie is the same as the one from the database.
3. 访问控制过滤器(Access Control Filter)
访问控制过滤器是检查当前用户是否能执行访问的controller action的初步授权模式。这种授权模式基于用户名,客户IP地址和访问类型,以命名为 "accessControl"的过滤器的方式提供.
小贴士: 访问控制过滤器适用于简单的验证。需要复杂的访问控制,需要使用将要讲解到的基于角色访问控制(role-based access (RBAC)).
在控制器(controller)里重载CController::filters方法设置访问过滤器来控制访问动作(看 Filter 了解更多过滤器设置信息)。
class PostController extends CController { ...... public function filters() { return array( 'accessControl', ); } }
在上面,设置的access control过滤器将应用于PostController
里每个动作。过滤器具体的授权规则通过重载控制器的CController::accessRules方法来指定。
class PostController extends CController { ...... public function accessRules() { return array( array('deny', 'actions'=>array('create', 'edit'), 'users'=>array('?'), ), array('allow', 'actions'=>array('delete'), 'roles'=>array('admin'), ), array('deny', 'actions'=>array('delete'), 'users'=>array('*'), ), ); } }
上面设定了三个规则,每个用个数组表示。数组的第一个元素不是'allow'
就是'deny'
,其他的是名-值成对形式设置规则参数的。上面的规则这样理解:create
和edit
动作不能被匿名执行;delete
动作可以被admin
角色的用户执行;delete
动作不能被任何人执行。
访问规则是一个一个按照设定的顺序一个一个来执行判断的。和当前判断模式(例如:用户名、角色、客户端IP、地址)相匹配的第一条规则决定授权的结果。如果这个规则是allow
,则动作可执行;如果是deny
,不能执行;如果没有规则匹配,动作可以执行。
info|提示:为了确保某类动作在没允许情况下不被执行,设置一个匹配所有人的
deny
规则在最后,类似如下:
return array( // ... 别的规则... // 以下匹配所有人规则拒绝'delete'动作 array('deny', 'action'=>'delete', ), );
因为如果没有设置规则匹配动作,动作缺省会被执行。
访问规则通过如下的上下文参数设置:
actions: 设置哪个动作匹配此规则。
users: 设置哪个用户匹配此规则。 此当前用户的name 被用来匹配. 三种设定字符在这里可以用:
*
: 任何用户,包括匿名和验证通过的用户。?
: 匿名用户。@
: 验证通过的用户。roles: 设定哪个角色匹配此规则。 这里用到了将在后面描述的role-based access control技术。In particular, the rule is applied if CWebUser::checkAccess returns true for one of the roles.提示,用户角色应该被设置成
allow
规则,因为角色代表能做某些事情。ips: 设定哪个客户端IP匹配此规则。
verbs: 设定哪种请求类型(例如:
GET
,POST
)匹配此规则。expression: 设定一个PHP表达式。它的值用来表明这条规则是否适用。在表达式,你可以使用一个叫
$user
的变量,它代表的是Yii::app()->user
。这个选项是在1.0.3版本里引入的。
授权处理结果(Handling Authorization Result)
当授权失败,即,用户不允许执行此动作,以下的两种可能将会产生:
如果用户没有登录和在用户部件中配置了loginUrl,浏览器将重定位网页到此配置URL。
否则一个错误代码401的HTTP例外将显示。
当配置loginUrl 属性,可以用相对和绝对URL。还可以使用数组通过CWebApplication::createUrl来生成URL。第一个元素将设置route 为登录控制器动作,其他为名-值成对形式的GET参数。如下,
array( ...... 'components'=>array( 'user'=>array( // 这实际上是默认值 'loginUrl'=>array('site/login'), ), ), )
如果浏览器重定位到登录页面,而且登录成功,我们将重定位浏览器到引起验证失败的页面。我们怎么知道这个值呢?我们可以通过用户部件的returnUrl 属性获得。我们因此可以用如下执行重定向:
Yii::app()->request->redirect(Yii::app()->user->returnUrl);
4. 基于角色的访问控制(Role-Based Access Control)
基于角色的访问控制提供了一种简单而又强大的集中访问控制。 请参阅维基文章了解更多详细的RBAC与其他较传统的访问控制模式的比较。
Yii 通过其 authManager 组件实现了分等级的 RBAC 结构。 在下文中,我们将首先介绍在此结构中用到的主要概念。然后讲解怎样定义用于授权的数据。在最后,我们看看如何利用这些授权数据执行访问检查。
概览(Overview)
在 Yii 的 RBAC 中,一个基本的概念是 授权项目(authorization item)。 一个授权项目就是一个做某件事的许可(例如新帖发布,用户管理)。根据其粒度和目标受众, 授权项目可分为 操作(operations),任务(tasks) 和角色(roles)。 一个角色由若干任务组成,一个任务由若干操作组成, 而一个操作就是一个许可,不可再分。 例如,我们有一个系统,它有一个 管理员
角色,它由 帖子管理
和 用户管理
任务组成。 用户管理
任务可以包含创建用户
,修改用户
和 删除用户
操作组成。 为保持灵活性,Yii 还允许一个角色包含其他角色或操作,一个任务可以包含其他操作,一个操作可以包括其他操作。
授权项目是通过它的名字唯一识别的。
一个授权项目可能与一个 业务规则 关联。 业务规则是一段 PHP 代码,在进行涉及授权项目的访问检查时将会被执行。 仅在执行返回 true 时,用户才会被视为拥有此授权项目所代表的权限许可。 例如,当定义一个updatePost(更新帖子)
操作时,我们可以添加一个检查当前用户 ID 是否与此帖子的作者 ID 相同的业务规则, 这样,只有作者自己才有更新帖子的权限。
通过授权项目,我们可以构建一个 授权等级体系 。在等级体系中,如果项目 A
由另外的项目 B
组成(或者说 A
继承了 B
所代表的权限),则 A
就是 B
的父项目。 一个授权项目可以有多个子项目,也可以有多个父项目。因此,授权等级体系是一个偏序图(partial-order graph)结构而不是一种树状结构。 在这种等级体系中,角色项目位于最顶层,操作项目位于最底层,而任务项目位于两者之间。
一旦有了授权等级体系,我们就可以将此体系中的角色分配给用户。 而一个用户一旦被赋予一个角色,他就会拥有此角色所代表的权限。 例如,如果我们赋予一个用户 管理员
的角色,他就会拥有管理员的权限,包括 帖子管理
和 用户管理
(以及相应的操作,例如 创建用户
)。
现在有趣的部分开始了,在一个控制器动作中,我们想检查当前用户是否可以删除指定的帖子。 利用 RBAC 等级体系和分配,可以很容易做到这一点。如下:
if(Yii::app()->user->checkAccess('deletePost')) { // 删除此帖 }
5. 配置授权管理器(Authorization Manager)
在我们准备定义一个授权等级体系并执行访问权限检查之前, 我们需要配置一下 authManager 应用组件。 Yii 提供了两种授权管理器: CPhpAuthManager 和 CDbAuthManager。前者将授权数据存储在一个 PHP 脚本文件中而后者存储在数据库中。 配置 authManager 应用组件时,我们需要指定使用哪个授权管理器组件类, 以及所选授权管理器组件的初始化属性值。例如:
return array( 'components'=>array( 'db'=>array( 'class'=>'CDbConnection', 'connectionString'=>'sqlite:path/to/file.db', ), 'authManager'=>array( 'class'=>'CDbAuthManager', 'connectionID'=>'db', ), ), );
然后,我们便可以使用 Yii::app()->authManager
访问 authManager 应用组件。
6. 定义授权等级体系
定义授权等级体总共分三步:定义授权项目,建立授权项目之间的关系,还要分配角色给用户。 authManager 应用组件提供了用于完成这三项任务的一系列 API 。
要定义一个授权项目,可调用下列方法之一,具体取决于项目的类型:
CAuthManager::createRole
CAuthManager::createTask
CAuthManager::createOperation
建立授权项目之后,我们就可以调用下列方法建立授权项目之间的关系:
CAuthManager::addItemChild
CAuthManager::removeItemChild
CAuthItem::addChild
CAuthItem::removeChild
最后,我们调用下列方法将角色分配给用户。
CAuthManager::assign
CAuthManager::revoke
下面的代码演示了使用 Yii 提供的 API 构建一个授权体系的例子:
$auth=Yii::app()->authManager; $auth->createOperation('createPost','create a post'); $auth->createOperation('readPost','read a post'); $auth->createOperation('updatePost','update a post'); $auth->createOperation('deletePost','delete a post'); $bizRule='return Yii::app()->user->id==$params["post"]->authID;'; $task=$auth->createTask('updateOwnPost','update a post by author himself',$bizRule); $task->addChild('updatePost'); $role=$auth->createRole('reader'); $role->addChild('readPost'); $role=$auth->createRole('author'); $role->addChild('reader'); $role->addChild('createPost'); $role->addChild('updateOwnPost'); $role=$auth->createRole('editor'); $role->addChild('reader'); $role->addChild('updatePost'); $role=$auth->createRole('admin'); $role->addChild('editor'); $role->addChild('author'); $role->addChild('deletePost'); $auth->assign('reader','readerA'); $auth->assign('author','authorB'); $auth->assign('editor','editorC'); $auth->assign('admin','adminD'); $auth->save();
特别提醒:如果没有在UserIdentity中重写getId方法,则上述assign没有问题,如果重写了getId返回用户的Id,那么相应的应该在assign语句中将相应的用户名修改成对应的用户Id,否则在使用checkAccess方法的时候无效!
建立此授权等级体系后,authManager 组件(例如 CPhpAuthManager, CDbAuthManager) 就会自动加载授权项目。因此,我们只需要运行上述代码一次,并不需要在每个请求中都要运行。
信息: 上面的示例看起来比较冗长拖沓,它主要用于演示的目的。 开发者通常需要开发一些用于管理的用户界面,这样最终用户可以通过界面更直观地建立一个授权等级体系。
7. 使用业务规则
在定义授权等级体系时,我们可以将 业务规则 关联到一个角色,一个任务,或者一个操作。 我们也可以在为一个用户分配角色时关联一个业务规则。 一个业务规则就是一段 PHP 代码,在我们执行权限检查时被执行。 代码返回的值用来决定是否将角色或分配应用到当前用户。 在上面的例子中,我们把一条业务规则关联到了updateOwnPost
任务。 在业务规则中,我们简单的检查了当前用户的 ID 是否与指定帖子的作者 ID 相同。$params
数组中的帖子(post)信息由开发者在执行权限检查时提供。
权限检查
要执行权限检查,我们首先需要知道授权项目的名字。 例如,要检查当前用户是否可以创建帖子,我们需要检查他是否拥有 createPost
所表示的权限。 然后我们调用 CWebUser::checkAccess 执行权限检查:
if(Yii::app()->user->checkAccess('createPost')) { // 创建帖子 }
如果授权规则关联了一条需要额外参数的业务规则,我们也可以传递给它。例如,要检查一个用户是否可以更新帖子, 我们可以通过 $params
传递帖子的数据:
$params=array('post'=>$post); if(Yii::app()->user->checkAccess('updateOwnPost',$params)) { // 更新帖子 }
使用默认角色
注意: 默认角色功能从 1.0.3 版本起可用。
许多 Web 程序需要一些可以分配给系统中所有或大多数用户的比较特殊的角色。 例如,我们可能想要分配一些权限给所有已通过身份验证的用户。如果我们特意指定并存储这些角色分配,就会引起很多维护上的麻烦。 我们可以利用 默认角色 解决这个问题。
默认角色就是一个隐式分配给每个用户的角色,这些用户包括通过身份验证的用户和游客。 我们不需要显式地将其分配给一个用户。 当 CWebUser::checkAccess 被调用时,将会首先检查默认的角色,就像它已经被分配给这个用户一样。
默认角色必须定义在 CAuthManager::defaultRoles 属性中。 例如,下面的配置声明了两个角色为默认角色:authenticated
和 guest
。
return array( 'components'=>array( 'authManager'=>array( 'class'=>'CDbAuthManager', 'defaultRoles'=>array('authenticated', 'guest'), ), ), );
由于默认角色会被分配给每个用户,它通常需要关联一个业务规则以确定角色是否真的要应用到用户。 例如,下面的代码定义了两个角色, authenticated
和 guest
,很高效地分别应用到了已通过身份验证的用户和游客用户。
$bizRule='return !Yii::app()->user->isGuest;'; $auth->createRole('authenticated', 'authenticated user', $bizRule); $bizRule='return Yii::app()->user->isGuest;'; $auth->createRole('guest', 'guest user', $bizRule);
以上就是Yii框架官方指南系列42——专题:验证和授权的内容,更多相关内容请关注PHP中文网(www.php.cn)!

여전히 인기있는 것은 사용 편의성, 유연성 및 강력한 생태계입니다. 1) 사용 편의성과 간단한 구문은 초보자에게 첫 번째 선택입니다. 2) 웹 개발, HTTP 요청 및 데이터베이스와의 우수한 상호 작용과 밀접하게 통합되었습니다. 3) 거대한 생태계는 풍부한 도구와 라이브러리를 제공합니다. 4) 활성 커뮤니티와 오픈 소스 자연은 새로운 요구와 기술 동향에 맞게 조정됩니다.

PHP와 Python은 웹 개발, 데이터 처리 및 자동화 작업에 널리 사용되는 고급 프로그래밍 언어입니다. 1.PHP는 종종 동적 웹 사이트 및 컨텐츠 관리 시스템을 구축하는 데 사용되며 Python은 종종 웹 프레임 워크 및 데이터 과학을 구축하는 데 사용됩니다. 2.PHP는 Echo를 사용하여 콘텐츠를 출력하고 Python은 인쇄를 사용합니다. 3. 객체 지향 프로그래밍을 지원하지만 구문과 키워드는 다릅니다. 4. PHP는 약한 유형 변환을 지원하는 반면, 파이썬은 더 엄격합니다. 5. PHP 성능 최적화에는 Opcache 및 비동기 프로그래밍 사용이 포함되며 Python은 Cprofile 및 비동기 프로그래밍을 사용합니다.

PHP는 주로 절차 적 프로그래밍이지만 객체 지향 프로그래밍 (OOP)도 지원합니다. Python은 OOP, 기능 및 절차 프로그래밍을 포함한 다양한 패러다임을 지원합니다. PHP는 웹 개발에 적합하며 Python은 데이터 분석 및 기계 학습과 같은 다양한 응용 프로그램에 적합합니다.

PHP는 1994 년에 시작되었으며 Rasmuslerdorf에 의해 개발되었습니다. 원래 웹 사이트 방문자를 추적하는 데 사용되었으며 점차 서버 측 스크립팅 언어로 진화했으며 웹 개발에 널리 사용되었습니다. Python은 1980 년대 후반 Guidovan Rossum에 의해 개발되었으며 1991 년에 처음 출시되었습니다. 코드 가독성과 단순성을 강조하며 과학 컴퓨팅, 데이터 분석 및 기타 분야에 적합합니다.

PHP는 웹 개발 및 빠른 프로토 타이핑에 적합하며 Python은 데이터 과학 및 기계 학습에 적합합니다. 1.PHP는 간단한 구문과 함께 동적 웹 개발에 사용되며 빠른 개발에 적합합니다. 2. Python은 간결한 구문을 가지고 있으며 여러 분야에 적합하며 강력한 라이브러리 생태계가 있습니다.

PHP는 현대화 프로세스에서 많은 웹 사이트 및 응용 프로그램을 지원하고 프레임 워크를 통해 개발 요구에 적응하기 때문에 여전히 중요합니다. 1.PHP7은 성능을 향상시키고 새로운 기능을 소개합니다. 2. Laravel, Symfony 및 Codeigniter와 같은 현대 프레임 워크는 개발을 단순화하고 코드 품질을 향상시킵니다. 3. 성능 최적화 및 모범 사례는 응용 프로그램 효율성을 더욱 향상시킵니다.

phphassignificallyimpactedwebdevelopmentandextendsbeyondit

PHP 유형은 코드 품질과 가독성을 향상시키기위한 프롬프트입니다. 1) 스칼라 유형 팁 : PHP7.0이므로 int, float 등과 같은 기능 매개 변수에 기본 데이터 유형을 지정할 수 있습니다. 2) 반환 유형 프롬프트 : 기능 반환 값 유형의 일관성을 확인하십시오. 3) Union 유형 프롬프트 : PHP8.0이므로 기능 매개 변수 또는 반환 값에 여러 유형을 지정할 수 있습니다. 4) Nullable 유형 프롬프트 : NULL 값을 포함하고 널 값을 반환 할 수있는 기능을 포함 할 수 있습니다.


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SecList
SecLists는 최고의 보안 테스터의 동반자입니다. 보안 평가 시 자주 사용되는 다양한 유형의 목록을 한 곳에 모아 놓은 것입니다. SecLists는 보안 테스터에게 필요할 수 있는 모든 목록을 편리하게 제공하여 보안 테스트를 더욱 효율적이고 생산적으로 만드는 데 도움이 됩니다. 목록 유형에는 사용자 이름, 비밀번호, URL, 퍼징 페이로드, 민감한 데이터 패턴, 웹 셸 등이 포함됩니다. 테스터는 이 저장소를 새로운 테스트 시스템으로 간단히 가져올 수 있으며 필요한 모든 유형의 목록에 액세스할 수 있습니다.

PhpStorm 맥 버전
최신(2018.2.1) 전문 PHP 통합 개발 도구

Atom Editor Mac 버전 다운로드
가장 인기 있는 오픈 소스 편집기

ZendStudio 13.5.1 맥
강력한 PHP 통합 개발 환경
