Oracle Technology Network (OTN) > Downloads, Discussions, and Documentation for Developers and DBAs

开发人员:PHP
  下载
PHP 5.2.5
Oracle 身份管理
  标签
php, identity, 全部

使用 PHP 创建 LDAP 目录服务


学习如何使用 PHP 在 OID 中创建 LDAP 目录服务

2007 年 12 月发布

Oracle Internet Directory (OID) 是一个利用了 Oracle 数据库的伸缩性、高可用性和安全性特性的符合 LDAP v3 标准的目录,它可以提供目录服务以存储并修改有关网络资源的信息。(例如,OID 充当 Oracle 身份管理的中心用户信息库。)

很多企业应用程序都使用 Java 命名和目录接口 (JNDI) 来访问 OID 中的目录服务。不过,当涉及到基于 PHP 的 Web 应用程序时 — 这样的应用程序数以百万计,同时其中很多都有着不断演变的安全性和认证要求 — 上述方法就显然不是好的选择了。改为使用将 PHP 和 OID 进行集成的方法则可以提供所需的目录服务。

在本文中,您将学习如何使用 PHP LDAP 扩展在 OID 中创建目录服务。您还将使用 LDAP PHP 类库来添加、修改、搜索和删除目录条目。

背景

目录服务是一个应用程序,用于存储、检索和修改有关网络资源(如网络用户)的信息。实际数据存储在数据库中。目录服务是数据库上的一个抽象层。轻型目录访问协议 (LDAP) 是一个用于访问目录服务的轻型协议,它也可定义目录条目的添加、搜索、修改和删除等操作。

一个“条目”是一组属性,由一个全局唯一的识别名称 (DN) 进行识别。每个目录条目的属性都有一个类型和一个或多个值。目录条目的 DN 中的属性按从右到左的层次进行排列,最右侧的属性为顶层条目,而最左侧在该级别上唯一的属性称作相对识别名称 (RDN)。

一个 DN 是一个 RDN 序列。表 1 讨论了属性类型的一些示例。

表 1 属性类型

属性类型 说明

o

组织

dc

域组件

ou

组织单位

cn

常用名称

uid

用户标识

dn

识别名称

mail

电子邮件地址

下面是一个 DN 示例:

cn=dvohra,cn=PUBLIC,dc=example,dc=com

在本例中,基本条目/根是 dc=example,dc=com,而 RDN 是 cn=dvohra。

安装 PHP

下载 Apache HTTP Server 2.0。要安装 Apache HTTP 服务器,双击 Apache Web 服务器应用程序 apache_2.2.3-win32-x86-no_ssl。

下载 PHP 5.2.5。将 PHP zip 文件 php-5.2.5-Win32.zip 解压缩至安装目录,如 C:/PHP。

将 PHP 5 的安装目录 C:/PHP 添加到 PATH 环境系统变量中。将 C:/PHP 目录中推荐的 php.init 文件修改为 php.ini。

在 Apache HTTP 服务器中安装 PHP 5。在 <Apache2>\conf\httpd.conf 文件中添加:

# For PHP 5 
LoadModule php5_module "C:/PHP/php5apache2.dll"
AddType application/x-httpd-php .php

# configure the path to php.ini
PHPIniDir "C:/PHP/"

<Apache2> 是 Apache 2 Web 服务器的安装目录,Apache Http Server 2.2.3 的默认安装目录是 C:\Program Files\Apache Software Foundation\Apache2.2。不过,对于本教程,Apache 2 web 服务器安装在 C:/Apache2 目录下。如果 PHP 5 的安装目录不是 C:/PHP,用实际安装目录替换 C:/PHP。

安装 Oracle Internet Directory

  1. 下载 Oracle 身份管理基础架构的 Disk1 和 Disk2 以及 Oracle Identity Federation 的 zip 文件。
  2. 将 disk1 解压缩至某目录。将 disk2 zip 文件解压缩至 disk1 所在的目录。
  3. 要安装 Oracle Internet Directory,单击 \install\setup 应用程序。Oracle Universal Installer 启动。
  4. 单击 Next
  5. 在 Specify File Locations 框中指定安装目录,单击 Next

 



图 1

选择 Oracle Application Server Infrastructure 10g,单击 Next。Oracle 应用服务器基础架构 10g 包含 OID 和 Oracle 数据库。



图 2

在 Select Installation Type 框中,选择 Identity Management and Metadata Repository,它将安装 Oracle Internet Directory 和 Oracle 数据库 10g。单击 Next



图 3

选择需要安装的默认 Oracle 应用服务器基础架构 10g 组件,单击 Next



图 4

检查安装前要求,单击 Next。选择默认的配置选项,单击 Next



图 5

选择默认的端口配置选项,单击 Next



图 6

在 Oracle Internet Directory 中指定命名空间以创建新用户。例如,指定 dc=example,dc=com,单击 Next



图 7

指定数据库配置选项或选择默认的数据库配置选项,单击 Next



图 8

指定数据库模式口令,单击 Next



图 9

指定 Oracle 应用服务器基础架构实例名。指定 ias_admin 管理员用户名的口令,单击 Next



图 10

单击 Install 安装 Oracle 应用服务器基础架构。



图 11

出现一个对话框,要求提供 Oracle 应用服务器 10g 的 disk 2。指定 disk2 的存放目录。



图 12

接着,配置助手进行安装。



图 13

单击 Next



图 14

单击 Exit 完成安装。



图 15

接着,启动 Oracle 目录管理器,它用于管理 OID。您需要先启动 OID Monitor 和一个 OID 服务器实例,然后才能使用 OID。使用以下命令启动 OID Monitor。

C:\>oidmon  start

使用以下命令启动一个 Oracle 目录服务器实例。

C:\>oidctl server=oidldapd instance=2 start
	

接着,启动 Oracle 目录管理器。在 Connect 框中,指定用户名为 orcladmin(这是一个超级用户),指定口令为 Oracle 应用服务器基础架构 10g 实例的口令。指定服务器为 localhost,端口为 389(默认端口)。单击 Login



图 16

Oracle 目录管理器启动。



图 17

 

安装 PHP LDAP 扩展

默认情况下没有启用 PHP LDAP 扩展。要启用 PHP LDAP 扩展,删除 php.ini 配置文件中以下行前面的“;”。

extension=php_ldap.dll

将 C:/PHP 目录中的 libeay32.dll 和 ssleay32.dll 复制到 C:/WINNT/system32 目录。重启 Apache Http 服务器。

PHP LDAP 类库提供各种用于创建 LDAP 目录服务的函数。表 2 讨论了一些常用的 PHP LDAP 函数。

表 2 PHP LDAP 函数

方法 说明

ldap_connect ( [string hostname [, int port]] )

连接到 LDAP 服务器。如果未指定主机名,将返回已打开链接的链接标识符。端口默认为 389。出错时返回 LDAP 链接标识符或 FALSE。

ldap_add ( resource link_identifier, string dn, array entry )

添加一个目录条目。参数 link_identifier 指定 LDAP 连接资源。参数 dn 指定目录条目的 dn。参数 entry 指定目录条目中的一组属性。如果完成添加操作,返回 TRUE;如果发生错误,返回 FALSE。

ldap_bind ( resource link_identifier [, string bind_rdn [, string bind_password]] )

使用指定的连接资源绑定到 LDAP 目录。如果完成绑定操作,返回 TRUE;如果发生错误,返回 FALSE。

ldap_unbind ( resource link_identifier )

取消与 LDAP 目录的绑定。如果完成取消绑定操作,返回 TRUE;如果发生错误,返回 FALSE。

ldap_close ( resource link_identifier )

取消与 LDAP 目录的绑定。

ldap_count_entries ( resource link_identifier, resource result_identifier )

返回 LDAP 搜索中的条目数。出错时返回 FALSE。

ldap_delete ( resource link_identifier, string dn )

删除一个目录条目。

ldap_error ( resource link_identifier )

返回上一 LDAP 命令的出错信息。

ldap_get_attributes ( resource link_identifier, resource result_entry_identifier )

返回目录条目中的一组属性。
出错时返回 FALSE。

ldap_first_entry ( resource link_identifier, resource result_identifier )

返回结果资源中的第一个条目。

ldap_next_entry ( resource link_identifier, resource result_entry_identifier )

返回结果资源中的下一条目。

ldap_get_entries ( resource link_identifier, resource result_identifier )

返回结果资源中的一组条目。

ldap_get_dn ( resource link_identifier, resource result_entry_identifier )

返回结果资源的 dn。

ldap_get_values ( resource link_identifier, resource result_entry_identifier, string attribute )

返回结果条目资源中某属性的全部属性值。

ldap_mod_add ( resource link_identifier, string dn, array entry )

为目录条目的属性添加属性值。

ldap_mod_del ( resource link_identifier, string dn, array entry )

删除 dn 属性的属性值。

ldap_mod_replace ( resource link_identifier, string dn, array entry )

替换 dn 的属性值。

ldap_modify ( resource link_identifier, string dn, array entry )

修改一个目录条目。

ldap_search ( resource link_identifier, string base_dn, string filter [, array attributes [, int attrsonly [, int sizelimit [, int timelimit [, int deref]]]]] )

使用基础 dn、指定的筛选器和一组属性(可选)来搜索目录。筛选器指定搜索的筛选方式,例如,仅搜索特定 objectclass 的属性。只有在要求属性类型时,才将 attrsonly 参数设置为 1。attrsonly 的默认值是 0,它用于获取属性类型和属性值。sizelimit 参数可用于限制返回条目的数量。Sizelimit 值为 0 等同于未设置 sizelimit。参数 timelimit 指定搜索操作的时间限制,单位为秒。

 

创建目录条目

接下来,在 OID LDAP 服务器中创建一个目录条目。例如,创建一个 JDeveloper 开发人员目录。LDAP 条目以 LDAP 数据交换格式 (LDIF) 表示,格式为 .ldif。条目格式如下所示。

dn: <distinguished name>
<attrdesc>: <attrvalue>
<attrdesc>: <attrvalue>

dn 表示目录条目的识别名称,attrdesc/attrvalue 表示目录条目的属性。我们将使用以下 dn 作为根/基础 DN。

cn=PUBLIC,cn=Users,dc=example,dc=com

基础 dn 的目录节点如下所示。所选的 dn 支持 top、person、organizationalPerson、inetorgperson、orcluser 和 orcluserV2 对象类。



图 18

每个目录条目用 dn 属性识别。objectclass 属性指定数据类型以及条目中必需的和可选的属性。针对目录条目所实施的不同的对象类,objectclass 属性可以有多个值。对象类形成一个类层次,一些常用的对象类包括 top、organization 和 organizationalPerson。所有的对象类都是对象类“top”的子类。每个 objectclass 都有必需的和可选的属性。

现在创建一个包含 top、person、organizationalPerson、inetorgperson、orcluser 和 orcluserV2 对象类的目录服务。“top”对象类没有任何必需的属性。Person 对象类的必需属性是“cn”和“sn”。OrganizationalPerson、inetorgperson、orcluser 和 orcluserV2 对象类没有任何必需的属性。在对象类 organizationalPerson 的目录条目中,可以指定的一些属性包括 title 和 telephoneNumber。

在 C:\Apache2\htdocs 目录中创建一个 PHP 脚本 add_entry.php。启动 OID LDAP 服务器(若还未启动)。首先,使用 ldap_connect() 函数创建一个与 OID 服务器的连接。

$ldaphost = "localhost";
	$ldapport = 389;
	$ldapconn = ldap_connect($ldaphost, $ldapport);

ldap_connect() 仅初始化连接参数并返回一个连接资源,但并不真正与 LDAP 服务器相连接。如果 ldap_connect() 方法没有返回错误,使用 LDAP_OPT_PROTOCOL_VERSION 将 LDAP 协议版本设置为 3。

ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);

接着,通过 ldap_bind() 函数使用连接资源、用户名和口令绑定到 LDAP 服务器。

$r=ldap_bind($ldapconn," cn=orcladmin,  "cn=PUBLIC,cn=Users,dc=example,dc=com","oid10admin");

要添加一个目录条目,创建一个包含一组属性的条目。例如,对“cn”属性作如下指定。

$directory_entry["cn"]="DeepakVohra";

在此示例目录条目中,您应当设置属性 cn、sn、title、telephoneNumber、physicalDeliveryOfficeName 和 facsimileTelephoneNumber。如果某属性具有多个值,属性值用二维数组进行指定。例如,objectclass 值按以下清单所示进行设置。

$directory_entry["objectclass"][0]="top";
$directory_entry["objectclass"][1]="person";
$directory_entry["objectclass"][2]="inetOrgPerson";
$directory_entry["objectclass"][3]="organizationalPerson";
$directory_entry["objectclass"][4]="orclUser";
$directory_entry["objectclass"][5]="orclUserV2";

指定待添加目录条目的 dn。

$dn="cn=DeepakVohra,cn=PUBLIC,cn=Users,dc=example,dc=com";

使用 ldap_add() 方法将目录条目添加到 LDAP 目录中。

$r=ldap_add($ldapconn, $dn, $directory_entry);

用于添加目录条目的 PHP 脚本 add_entry.php 如下所示。

<?php
$ldaphost = "localhost";  
$ldapport = 389;


$ldapconn = ldap_connect($ldaphost, $ldapport); 

if ($ldapconn) {
   ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
   $r=ldap_bind($ldapconn,"cn=orcladmin","oid10admin");

   if(!$r){echo "User did not bind to LDAP Server";}
   else echo "User was bound to LDAP Server"; 

   $directory_entry["cn"]="DeepakVohra";
   $directory_entry["sn"]="Vohra";
   $directory_entry["objectclass"][0]="top";
   $directory_entry["objectclass"][1]="person";
   $directory_entry["objectclass"][2]="inetOrgPerson";
   $directory_entry["objectclass"][3]="organizationalPerson";
   $directory_entry["objectclass"][4]="orclUser";
   $directory_entry["objectclass"][5]="orclUserV2";


   $directory_entry["title"]="PHP Developer";
   $directory_entry["telephoneNumber"]="555 1234";
   $directory_entry["physicalDeliveryOfficeName"]="JDeveloper";
   $directory_entry["facsimileTelephoneNumber"]="555 5678";

   $dn="cn=DeepakVohra,cn=PUBLIC,cn=Users,dc=example,dc=com";

   $r=ldap_add($ldapconn, $dn, $directory_entry);
   if(!$r) echo "Directory Entry not Added.";
   else echo "Directory Entry Added";
   ldap_close($ldapconn);
} else {
   echo ldap_error($ldapconn);}
?>

将 PHP 脚本 add_entry.php 复制到 C:\Apache2\htdocs 目录。使用 URL http://localhost/add_entry.php 运行 PHP 脚本。在 Oracle 目录管理器中,使用 View > Refresh 刷新目录条目。



图 19

添加了一个目录条目,如 Oracle 目录管理器中所示。



图 20

修改目录

在本节中,您将修改前面添加的目录条目。创建 PHP 脚本 modify_entry.php 以修改目录条目。

首先,使用 ldap_connect() 方法创建连接资源。

$ldaphost = "localhost";  
$ldapport = 389;               
$ldapconn = ldap_connect($ldaphost, $ldapport);

如果已创建连接资源,则将 LDAP 协议版本设置为 3,并使用 ldap_bind() 函数与 LDAP 目录进行绑定。

ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
$r=ldap_bind($ldapconn,"cn=orcladmin","oid10admin");

使用修改后的值创建一组目录条目属性。例如,修改“title”属性值和 physicalDeliveryOfficeName 属性值。

$directory_entry["title"]="Web  Developer";
$directory_entry["physicalDeliveryOfficeName"]="Oracle  JDeveloper";

只有要修改的属性才需要在属性数组中进行指定。

每个目录条目用识别名称进行识别。指定待修改目录条目的 dn。

$dn="cn=DeepakVohra,cn=PUBLIC,cn=Users,dc=example,dc=com";

使用 ldap_modify() 函数修改目录条目。

$r=ldap_modify($ldapconn,$dn,  $directory_entry);

用于修改目录条目的 PHP 脚本 ldap_modify.php 见清单 2。

清单 2 modify_entry.php

<?php
$ldaphost = "localhost";  
$ldapport = 389;

$ldapconn = ldap_connect($ldaphost, $ldapport); 

if ($ldapconn) {
   ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
   $r=ldap_bind($ldapconn,"cn=orcladmin","oid10admin"); 
	   
   
   $directory_entry["title"]="Web Developer";
   $directory_entry["physicalDeliveryOfficeName"]="Oracle JDeveloper";
   
   $dn="cn=DeepakVohra,cn=PUBLIC,cn=Users,dc=example,dc=com";

   $r=ldap_modify($ldapconn,$dn, $directory_entry);
   if(!$r) echo "Directory Entry Not Modified";
    else echo "Directory Entry Modified";
   
   
   ldap_close($ldapconn);
} else {
   echo ldap_error($ldapconn);
}
?>

复制 modify_entry.php 到 C:\Apache2\htdocs 目录。
使用 URL http://localhost/modify_entry.php 运行该脚本。目录条目已修改,如 Oracle 目录管理器中所示。



图 21

搜索目录

在本节中,您将使用 PHTML(嵌入在 HTML 中的 PHP)脚本搜索目录条目并在 HTML 中显示结果。将 .phtml 扩展添加到 C:/Apache2/conf/httpd.conf 文件的以下 Apache 2 配置指令中。

AddType application/x-httpd-php .php .phtml

重启 Apache 2 服务器。在 C:/Apache2/htdocs 目录中创建一个 PHTML 脚本 search_entry.phtml。首先,使用 ldap_connect() 方法为 LDAP 服务器连接创建一个连接资源。

$ldaphost = "localhost";
$ldapport = 389;
$ldapconn = ldap_connect($ldaphost, $ldapport);

如果已创建连接资源,则将 LDAP 协议版本设置为 3,同时目录服务器要使用 ldap_bind() 方法。

ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
$r=ldap_bind($ldapconn,"cn=orcladmin","oid10admin");

接着,指定要为其检索属性值的属性数组。默认情况下,检索所有的属性。

$attribute_array=array("cn", "sn",  "title",  "telephoneNumber","physicalDeliveryOfficeName",
   "facsimileTelephoneNumber",  "objectclass");

指定待搜索目录条目的 dn。

$dn="cn=DeepakVohra,cn=PUBLIC,cn=Users,dc=example,dc=com";

指定搜索的筛选器。例如,指定搜索所有 objectclass 的筛选器。

$filter = "(objectclass=*)";

使用 ldap_search() 方法搜索目录。

$sr=ldap_search($ldapconn,$dn, $filter, $attribute_array);

使用 ldap_get_entries() 方法检索搜索结果中的目录条目。

$directory_entries= ldap_get_entries($ldapconn, $sr);

创建 HTML 表以显示搜索结果。为表添加标题行。检索每个属性的值并将其添加到表中。目录条目搜索结果是一组条目。第一个目录条目通过表达式 $directory_entries[0] 进行访问。

一个目录条目包含一组属性。目录条目中的属性通过在属性数组中指定属性名进行访问。(例如,“cn”属性通过表达式 $directory_entries[0]['cn'] 进行访问。)

一个属性由一组值构成,数组值通过指定属性值数组索引进行访问。objectclass 属性有多个值。例如,objectclass 属性值数组中的第一个值通过表达式 $directory_entries[0]['objectclass'][0] 进行访问。数组中属性值的数目可通过“count”属性获得。例如,objectclass 属性的值的数目获取方式如下。

$count=$directory_entries[0]['objectclass']["count"];

从搜索结果中检索属性值并添加到表中。例如,“cn”属性行的添加如下所示。

<tr><td>cn</td><td><?php echo  $directory_entries[0]['cn'][0]; ?></td></tr>

如果一个属性有多个值(如 objectclass 属性),使用 () 循环来遍历属性值并进行输出。

for ($i=0; $i<$count; $i++){
	print  $directory_entries[0]['objectclass'][$i]."<br>";
}

search_entry.phtml 脚本见清单 3。

清单 3 search_entry.phtml

<?php
$ldaphost = "localhost";  
$ldapport = 389;               


$ldapconn = ldap_connect($ldaphost, $ldapport); 

if ($ldapconn) {
   ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
   $r=ldap_bind($ldapconn,"cn=orcladmin","phpldap");

   $attribute_array=array("cn", "sn", "title", "telephoneNumber",
     "physicalDeliveryOfficeName","facsimileTelephoneNumber", 

"objectclass");
   
   $dn="cn=DeepakVohra,cn=PUBLIC,cn=Users,dc=example,dc=com";   $filter = "(objectclass=*)";
   $sr=ldap_search($ldapconn,$dn, $filter, $attribute_array);
  $directory_entries= ldap_get_entries($ldapconn, $sr);
  ldap_close($ldapconn);

   
} else {
echo ldap_error($ldapconn);}
?>
<HTML>
 <HEAD>
  <TITLE> Directory Entry</TITLE>
 </HEAD
 <BODY>
<p> </p>
 <table border>
<tr><th>Attribute</th><th>Value</th></tr>

<tr><td>cn</td><td><?php echo $directory_entries[0]['cn'][0]; ?></td></tr>
<tr><td>sn</td><td><?php print $directory_entries[0]['sn'][0]; ?></td></tr>
<tr><td>title</td><td><?php print $directory_entries[0]['title'][0]; ?></td></tr>
<tr><td>telephoneNumber</td><td>
   <?php print $directory_entries[0]['telephonenumber'][0]; ?></td></tr>
<tr><td>physicalDeliveryOfficeName</td><td>
   <?php print $directory_entries[0]['physicaldeliveryofficename'][0]; ?></td></tr>
<tr><td>facsimileTelephoneNumber</td><td>
   <?php print $directory_entries[0]['facsimiletelephonenumber'][0]; ?></td></tr>

<tr><td>objectclass</td><td>
<?php 

$count=$directory_entries[0]['objectclass']["count"];

for ($i=0; $i<$count; $i++){
   print $directory_entries[0]['objectclass'][$i]."<br>";
}

?></td></tr>

</table>
</BODY>
</HTML>
要搜索某一目录条目,使用 URL http://localhost/search_entry.phtml 运行 search_entry.phtml 脚本。显示目录条目属性。

 



图 22

删除目录

在本节中,您将删除一个目录条目。?在 C:/Apache2/htdocs 目录中创建一个 PHP 脚本 delete_entry.php。首先,使用 ldap_connect() 方法获得一个用于 LDAP 服务器的连接资源。

$ldaphost = "localhost";
$ldapport = 389;
$ldapconn = ldap_connect($ldaphost,  $ldapport);

如果已创建连接资源,则将 LDAP 协议版本设置为 3,并使用 ldap_bind() 函数进行绑定。

ldap_set_option($ldapconn,  LDAP_OPT_PROTOCOL_VERSION, 3);
$r=ldap_bind($ldapconn,"cn=orcladmin","oid10admin");

指定待删除目录条目的 dn。

$dn="cn=DeepakVohra,cn=PUBLIC,cn=Users,dc=example,dc=com";

使用 ldap_delete() 方法删除目录条目。

$r=ldap_delete($ldapconn, $dn);

PHP 脚本 delete_entry.php 见清单 4。

清单 4 delete_entry.php

<?php
$ldaphost = "localhost";  
$ldapport = 389;

$ldapconn = ldap_connect($ldaphost, $ldapport); 

if ($ldapconn) {
   ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
   $r=ldap_bind($ldapconn,"cn=orcladmin","oid10admin");
   
   $dn="cn=DeepakVohra,cn=PUBLIC,cn=Users,dc=example,dc=com";
   
   $r=ldap_delete($ldapconn, $dn);
   if(!$r) echo "Directory Entry Not Deleted";
   else echo "Directory Entry Deleted";
   ldap_close($ldapconn);
} else {
   echo ldap_error($ldapconn);
}
?>

要删除一个目录条目,使用 URL http://localhost/delete_entry.php 调用 delete_entry.php 脚本。目录条目已删除,如 Oracle 目录管理器中所示。



图 23

恭喜!您已经学会了如何使用 PHP 在 OID 中创建和删除 LDAP 目录服务。


Deepak Vohra (dvohra09@yahoo.com) 是一位 Sun 认证的 Java 程序员和 NuBean 顾问,经常在 onjava.com、XML JournalWebLogic Developer's Journal 和 OTN 上发表文章。

E-mail this page
Printer View Printer View