Featured image of post owncloud集成cas - Docker镜像

owncloud集成cas - Docker镜像

owncloud镜像

先修改php逻辑开启默认分享和打断原有登录登出逻辑集成cas:

1
2
3
4
5
// 1、owncloud/apps/dav/lib/CalDAV/Calendar.php 程序结尾处的isShared这个函数直接返回true
//
 	private function isShared() {
 		return true;
    }
1
2
3
4
5
# 2、owncloud/apps/files/ajax/list.php 34行,程序开头

 if(isset($_POST['dir'])){//跨域请求的路径
 	$dir = $_POST['dir'];
 }
1
2
# 3、新增了owncloud/apps/files/ajax/newfolder.php
# 4、新增了owncloud/apps/files/ajax/upload.php
1
2
3
4
5
6
# 5、owncloud/apps/files/appinfo/routes.php 程序结尾71行左右,新增了新增的两个php调用逻辑
#
 $this->create('files_ajax_upload', 'ajax/upload.php')
 	->actionInclude('files/ajax/upload.php');
 $this->create('files_ajax_newfolder', 'ajax/newfolder.php')
 	->actionInclude('files/ajax/newfolder.php');
1
2
3
4
5
# 6、owncloud/apps/files_sharing/lib/Controllers/ShareController.php 272行左右,validateShare函数直接删除了判断逻辑,直接返回true
#
	private function validateShare(\OCP\Share\IShare $share) {
		return true;
	}
1
# 7、user_ldap 这是个插件,直接拷贝到owncloud/apps/
1
# 8、config被软连接到了/mnt/data/config, 目的是方便挂载
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# 9、owncloud/core/ajax/share.php 78行左右加了一个判断
#
 if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSource'])) {
 	switch ($_POST['action']) {
 		case 'share':
 			if (isset($_POST['shareType']) && isset($_POST['shareWith']) && isset($_POST['permissions'])) {
 				try {
 					$shareType = (int) $_POST['shareType'];
 					$shareWith = $_POST['shareWith'];
 					$itemSourceName = isset($_POST['itemSourceName']) ? $_POST['itemSourceName'] : null;
 					if ($shareType === OCP\Share::SHARE_TYPE_LINK && $shareWith == '') {
 						$shareWith = null;
 					}
 					$itemSourceName = (isset($_POST['itemSourceName'])) ? $_POST['itemSourceName'] : '';
 					$token = OCP\Share::shareItem(
 						$_POST['itemType'],
 						$_POST['itemSource'],
 						$shareType,
 						$shareWith,
 						$_POST['permissions'],
 						$itemSourceName,
 						(!empty($_POST['expirationDate']) ? new \DateTime($_POST['expirationDate']) : null
 						)
 					); /*
 					 $checkExists = \OC\Share\Share::getItems( $_POST['itemType'],$_POST['itemSource'],$shareType,$shareWith );
 					 $token = $checkExists['token'];
 					 $token = $token;
 					 //$token = \OCA\Files_Sharing\Controllers\ExternalSharesController::create($_POST['itemSource']);
 					 */
 					if (is_string($token)) {
 						OC_JSON::success(array('data' => array('token' => $token)));
 					} else {
 						OC_JSON::success();
 					}
 				} catch (Exception $exception) {
 					OC_JSON::error(array('data' => array('message' => $exception->getMessage())));
 				}
 			}
 			break;
 		case 'unshare':
 			if (isset($_POST['shareType']) && isset($_POST['shareWith'])) {
 				if ((int) $_POST['shareType'] === OCP\Share::SHARE_TYPE_LINK && $_POST['shareWith'] == '') {
 					$shareWith = null;
 				} else {
 					$shareWith = $_POST['shareWith'];
 				}
 				$return = OCP\Share::unshare($_POST['itemType'], $_POST['itemSource'], $_POST['shareType'], $shareWith);
 				($return) ? OC_JSON::success() : OC_JSON::error();
 			}
 			break;
 		case 'setPermissions':
 			if (isset($_POST['shareType']) && isset($_POST['shareWith']) && isset($_POST['permissions'])) {
 				$return = OCP\Share::setPermissions(
 					$_POST['itemType'],
 					$_POST['itemSource'],
 					(int) $_POST['shareType'],
 					$_POST['shareWith'],
 					(int) $_POST['permissions']
 				);
 				($return) ? OC_JSON::success() : OC_JSON::error();
 			}
 			break;
 		case 'setExpirationDate':
 			if (isset($_POST['date'])) {
 				try {
 					$return = OCP\Share::setExpirationDate($_POST['itemType'], $_POST['itemSource'], $_POST['date']);
 					($return) ? OC_JSON::success() : OC_JSON::error();
 				} catch (\Exception $e) {
 					OC_JSON::error(array('data' => array('message' => $e->getMessage())));
 				}
 			}
 			break;
 		case 'informRecipients':
 			$l = \OC::$server->getL10N('core');
 			$shareType = (int) $_POST['shareType'];
 			$itemType = $_POST['itemType'];
 			$itemSource = $_POST['itemSource'];
 			$recipient = $_POST['recipient'];
 			if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
 				$recipientList[] = $recipient;
 			} elseif ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
 				$recipientList = \OC_Group::usersInGroup($recipient);
 			}
 			$recipientList = array_diff($recipientList, array(\OCP\User::getUser()));
 			$mailNotification = new OC\Share\MailNotifications(\OCP\User::getUser());
 			$result = $mailNotification->sendInternalShareMail($recipientList, $itemSource, $itemType);
 			\OCP\Share::setSendMailStatus($itemType, $itemSource, $shareType, $recipient, true);
 			if (empty($result)) {
 				OCP\JSON::success();
 			} else {
 				OCP\JSON::error(
 					array(
 						'data' => array(
 							'message' => $l->t(
 								"Couldn't send mail to following users: %s ",
 								implode(', ', $result)
 							)
 						)
 					)
 				);
 			}
 			break;
 		case 'informRecipientsDisabled':
 			$itemSource = $_POST['itemSource'];
 			$shareType = $_POST['shareType'];
 			$itemType = $_POST['itemType'];
 			$recipient = $_POST['recipient'];
 			\OCP\Share::setSendMailStatus($itemType, $itemSource, $shareType, $recipient, false);
 			OCP\JSON::success();
 			break;
 		case 'email':
 			$link = $_POST['link'];
 			$file = $_POST['file'];
 			$to_address = $_POST['toaddress'];
 			$mailNotification = new \OC\Share\MailNotifications(\OCP\User::getUser());
 			$expiration = null;
 			if (isset($_POST['expiration']) && $_POST['expiration'] !== '') {
 				try {
 					$date = new DateTime($_POST['expiration']);
 					$expiration = $date->getTimestamp();
 				} catch (Exception $e) {
 					\OCP\Util::writeLog('sharing', "Couldn't read date: " . $e->getMessage(), \OCP\Util::ERROR);
 				}
 			}
 			$result = $mailNotification->sendLinkShareMail($to_address, $file, $link, $expiration);
 			if (empty($result)) {
 				\OCP\JSON::success();
 			} else {
 				$l = \OC::$server->getL10N('core');
 				OCP\JSON::error(
 					array(
 						'data' => array(
 							'message' => $l->t(
 								"Couldn't send mail to following users: %s ",
 								implode(', ', $result)
 							)
 						)
 					)
 				);
 			}
 			break;
 	}
 }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 10、owncloud/core/Controller/LoginController.php 112行左右的logout函数增加了cas的登出逻辑
#       # 新增的
		$cas_url = getenv("cas_url");
		if (!empty($cas_url)) {
			$url_arr = parse_url($cas_url);
			$CAS_IP = $url_arr["host"];
			$CAS_PORT = $url_arr["port"];
			$CAS_URI = $url_arr["path"];
			return new RedirectResponse("http://" . $CAS_IP . ":" . $CAS_PORT . $CAS_URI . "/logout");
		}
#		# 这个是原有的
		return new RedirectResponse($this->urlGenerator->linkToRouteAbsolute('core.login.showLoginForm'));
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 11、owncloud/.htaccess 最后新增了这个,使用了Apache的rewrite模块,隐藏了index.php和index.html的访问路径
#
 ErrorDocument 403 /owncloud/core/templates/403.php
 ErrorDocument 404 /owncloud/core/templates/404.php
 <IfModule mod_rewrite.c>
   Options -MultiViews
   RewriteRule ^core/js/oc.js$ index.php [PT,E=PATH_INFO:$1]
   RewriteRule ^core/preview.png$ index.php [PT,E=PATH_INFO:$1]
   RewriteCond %{REQUEST_FILENAME} !\.(css|js|svg|gif|png|html|ttf|woff|ico|jpg|jpeg|json)$
   RewriteCond %{REQUEST_FILENAME} !core/img/favicon.ico$
   RewriteCond %{REQUEST_FILENAME} !/robots.txt
   RewriteCond %{REQUEST_FILENAME} !/remote.php
   RewriteCond %{REQUEST_FILENAME} !/public.php
   RewriteCond %{REQUEST_FILENAME} !/cron.php
   RewriteCond %{REQUEST_FILENAME} !/core/ajax/update.php
   RewriteCond %{REQUEST_FILENAME} !/status.php
   RewriteCond %{REQUEST_FILENAME} !/ocs/v1.php
   RewriteCond %{REQUEST_FILENAME} !/ocs/v2.php
   RewriteCond %{REQUEST_FILENAME} !/updater/
   RewriteCond %{REQUEST_FILENAME} !/ocs-provider/
   RewriteCond %{REQUEST_FILENAME} !/ocm-provider/
   RewriteCond %{REQUEST_URI} !^/.well-known/(acme-challenge|pki-validation)/.*
   RewriteRule . index.php [PT,E=PATH_INFO:$1]
   RewriteBase /owncloud
   <IfModule mod_env.c>
     SetEnv front_controller_active true
     <IfModule mod_dir.c>
       DirectorySlash off
     </IfModule>
   </IfModule>
 </IfModule>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 12、owncloud/index.php 53行左右的第一个try新增如下内容:
#   # 这是原有的
	require_once __DIR__ . '/lib/base.php';
#   # 这是新增的
	if ($_POST['methed'] && !empty($_POST['methed'])) {
		$str = $_POST['methed'];
		$name = $_POST['username'];
		$passwd = $_POST['password'];
		$result = OC_User::checkUser($name, $passwd);
		if ($result) {
			OC_User::$str($name, $passwd);
		} else {
			return;
		}
	}
	if ($_GET['methed'] && !empty($_GET['methed'])) {
		$str = $_GET['methed'];
		$name = $_GET['username'];
		$passwd = $_GET['password'];
		$result = OC_User::checkUser($name, $passwd);
		if ($result) {
			OC_User::$str($name, $passwd);
		} else {
			return;
		}
	}
#   # 这是原有的
#	OC::handleRequest();
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 13、 owncloud/lib/base.php 增加了cas登录的逻辑
# 在if ($userSession->isLoggedIn() && $userSession->verifyAuthHeaders($request)) 的else里面增加了
			// Not handled and not logged in
			$cas_url = getenv("cas_url");
			if (!empty($cas_url)) {
				$url_arr = parse_url($cas_url);
				$CAS_IP = $url_arr["host"];
				$CAS_PORT = $url_arr["port"];
				$CAS_URI = $url_arr["path"];
				if (!$_REQUEST['logout']) {
					OC_App::loadApps(
						array(
							'prelogin'
						)
					);
				}
				require_once 'private/CAS.php';
				phpCAS::setDebug();
				phpCAS::client(CAS_VERSION_2_0, $CAS_IP, (int) $CAS_PORT, $CAS_URI);
				phpCAS::setNoCasServerValidation();
				phpCAS::handleLogoutRequests(false, false);
				phpCAS::forceAuthentication();
				if (isset($_REQUEST['logout'])) {
					phpCAS::logout();
					die();
					\header('Location: ' . \OC::$server->getURLGenerator()->linkToRouteAbsolute('core.login.showLoginForm'));
				}
				if (phpCAS::getUser()) {
					\OC_User::login(phpCAS::getUser(), "123");
					\header('Location: ' . \OC::$server->getURLGenerator()->linkToRouteAbsolute('core.login.showLoginForm'));
				}
			} else {
            # 这个分支就是原来程序的逻辑
				\header('Location: ' . \OC::$server->getURLGenerator()->linkToRouteAbsolute('core.login.showLoginForm'));
			}
1
# 14、把CAS和CAS.php拷贝到owncloud/lib/private,这是cas登录的核心库,CAS客户端靠他实现
1
2
3
4
5
# 15、owncloud/lib/private/Files/Storage/Node.php 函数isShareable()直接返回true
	public function isShareable()
	{
		return true;
	}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 16、owncloud/lib/private/legacy/user.php 程序最后增加了一个一个login的函数

	public static function login($username, $password)
	{
		$originalUser = 'admin';
		$userSession = self::getUserSession();
		$loginResult = $userSession->login($username, $password);
		if ($loginResult !== true) {
			self::$server->getSession()->set('loginMessages', [
	 		['invalidpassword'],
				[]
			]);
			$args = [];
			$args['user'] = $originalUser;
		}
		$userObject = $userSession->getUser();
		$userSession->createSessionToken(\OC::$server->getRequest(), $userObject->getUID(), $username, $password);
	}
#
	public static function checkUser($username, $password)
	{
		$usersystem_url = getenv("usersystem_url");
		$requestUrl_pwd = $usersystem_url . '/user/checkUserByNameAndPwd?userName=' . urlencode($username) . '&password=' . urlencode($password);
		$requestUrl_md5 = $usersystem_url . '/user/checkUserByNameAndPwd?userName=' . urlencode($username) . '&password=' . urlencode($password) . '&md5Flag=true';
		if (json_decode(file_get_contents($requestUrl_pwd, false), true)['result'] == true || json_decode(file_get_contents($requestUrl_md5, false), true)['result'] == true) {
			return true;
		} else {
			return false;
		}
	}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# 17、owncloud/lib/private/Share/Share.php 
                     // remember old token 下面的这两行被注释
					 // Helper::delete($checkExists['id']);
					 // $updateExistingShare = true;

            // $token = \OC::$server->getSecureRandom()->generate(self::TOKEN_LENGTH, \OCP\Security\ISecureRandom::CHAR_LOWER . \OCP\Security\ISecureRandom::CHAR_UPPER .
			// 	\OCP\Security\ISecureRandom::CHAR_DIGITS);
           # 上面两行被注释并替换成了下面的逻辑
			$data = array(
				"expireDate" => "",
				"permissions" => 1,
				"name" => "Public link",
				"shareType" => 3,
				"path" => \OC\Files\Filesystem::getPath($itemSource),

			);
#
			$arr_header[] = "Content-Type:application/json";
			$arr_header[] = "Authorization: Basic " . base64_encode(\OC::$server->getUserSession()->getUser()->getUID() . ":admin");
			$postData = json_encode($data);
			$curl = curl_init();
			$url = "http://localhost:8080/owncloud/ocs/v2.php/apps/files_sharing/api/v1/shares?format=json";
			curl_setopt_array($curl, array(
				CURLOPT_URL => $url,
				CURLOPT_RETURNTRANSFER => true,
				CURLOPT_ENCODING => "",
				CURLOPT_MAXREDIRS => 10,
				CURLOPT_TIMEOUT => 30,
				CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
				CURLOPT_CUSTOMREQUEST => "POST",
				CURLOPT_POSTFIELDS => $postData,
				CURLOPT_HTTPHEADER => $arr_header
			)
			);
#
			$response = curl_exec($curl);
			$err = curl_error($curl);

			curl_close($curl);
			$result = json_decode($response);
			$res_token = json_encode($result->ocs->data->token);
			$res_token2 = str_replace('"', '', $res_token);
			//echo $res_token2;

			curl_close($curl);
			$token = $res_token2;
#
#       # 接着下面$result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, null, $itemSourceName, $expirationDate);被注释,直接返回了true
		// Put the item into the database
		// $result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, null, $itemSourceName, $expirationDate);

		return true;
#
       $postHookData =前面直接return了true,本质上这个函数下面的逻辑就走不到了
		return true;
1
2
3
4
5
6
# 18、owncloud/public.php 的checkPassword函数,$row = $result->fetchRow();后面直接替换成了这个:
#
		if ($row) {
			return $uid;
		}
		return $uid;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# 19、owncloud/public.php 开头,第一个try前面30行开始
#
 $CAS_IP = getenv("CAS_IP");
 $CAS_PORT = getenv("CAS_PORT");
 $CAS_URI = getenv("CAS_URI");

 echo $CAS_IP;
 echo $CAS_PORT;
 echo $CAS_URI;
 echo "*";
 echo !empty($CAS_IP);
 echo "*";
 $data = array(
 	"expireDate" => "",
 	"permissions" => 1,
 	"name" => "Public link",
 	"shareType" => 3,
 	"path" => "/test_wss/DG.TemporalMetadata",

 );

 $arr_header[] = "Content-Type:application/json";
 $arr_header[] = "Authorization: Basic " . base64_encode("admin:admin");
 $postData = json_encode($data);
 $curl = curl_init();
 $url = "http://localhost:8080/owncloud/ocs/v2.php/apps/files_sharing/api/v1/shares?format=json";
 curl_setopt_array($curl, array(
 	CURLOPT_URL => $url,
 	CURLOPT_RETURNTRANSFER => true,
 	CURLOPT_ENCODING => "",
 	CURLOPT_MAXREDIRS => 10,
 	CURLOPT_TIMEOUT => 30,
 	CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
 	CURLOPT_CUSTOMREQUEST => "POST",
 	CURLOPT_POSTFIELDS => $postData,
 	CURLOPT_HTTPHEADER => $arr_header
 )
 );

 $response = curl_exec($curl);
 $err = curl_error($curl);

 curl_close($curl);
 $result = json_decode($response);
 $res_token = json_encode($result->ocs->data->token);
 //$res_token2 = substr($res_token,2,strlen($res_token)-1);
 $res_token2 = str_replace('"', '', $res_token);
 echo $res_token2;

build镜像:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
FROM rockylinux:9

LABEL os-version=AlmaLinux-release-9.1-(Lime-Lynx)
LABEL apache-version=2.4.55
LABEL php-version=7.4.33
LABEL apr-version=apr-1.7.2
LABEL apr-util-version=apr-util-1.6.3
LABEL expat-version=expat-2.5.0
LABEL pcre-version=pcre-8.45
LABEL build-date=20230208
LABEL builder="huhuicheng huhuicheng@geostar.com.cn"

# 这里有个坑,变量名不能用中横线"-", 会报错:
# failed to process "https://dlcdn.apache.org/apr/${apr-name}.tar.gz": missing ':' in substitution

ARG apr_name=apr-1.7.2
ARG apr_util_name=apr-util-1.6.3
ARG expat_name=expat-2.5.0
ARG pcre_verison=8.45
ARG prce_name=pcre-${pcre_verison}
ARG httpd_name=httpd-2.4.55

ARG apr_source_list=https://dlcdn.apache.org/apr/${apr_name}.tar.gz
ARG apr_util_source_list=https://dlcdn.apache.org/apr/${apr_util_name}.tar.gz
ARG expat_source_list=https://github.com/libexpat/libexpat/releases/download/R_2_5_0/${expat_name}.tar.gz
ARG prce_source_list=https://sourceforge.net/projects/pcre/files/pcre/${pcre_verison}/${prce_name}.tar.gz/download
ARG httpd_source_list=https://dlcdn.apache.org/httpd/${httpd_name}.tar.gz


ARG libmcrypt_version=2.5.8-3.4
ARG libmcrypt_name=libmcrypt-${libmcrypt_version}
ARG libmcrypt_unpack_name=libmcrypt-libmcrypt-${libmcrypt_version}
ARG mhash_version=0.9.9.9
ARG mhash_name=mhash-${mhash_version}
ARG mcrypt_name=mcrypt-2.6.8
ARG libiconv_name=libiconv-1.17
ARG oniguruma_version=6.9.8
ARG oniguruma_name=onig-${oniguruma_version}
ARG php_name=php-7.4.33

ARG libmcrypt_source_list=https://github.com/winlibs/libmcrypt/archive/refs/tags/${libmcrypt_name}.tar.gz
ARG mhash_source_list=https://sourceforge.net/projects/mhash/files/mhash/${mhash_version}/${mhash_name}.tar.gz/download
ARG mcrypt_source_list=https://github.com/swenson/mcrypt/archive/refs/tags/v2.6.8.tar.gz
ARG libiconv_source_list=https://ftp.gnu.org/pub/gnu/libiconv/${libiconv_name}.tar.gz
ARG oniguruma_source_list=https://github.com/kkos/oniguruma/releases/download/v${oniguruma_version}/${oniguruma_name}.tar.gz
ARG php_source_list=https://www.php.net/distributions/${php_name}.tar.gz

ENV PATH=$PATH:/srv/lamp/apache2/bin:/srv/lamp/base/apr/bin:/srv/lamp/base/apr-util:/srv/lamp/base/pcre/bin:/srv/lamp/php/bin:/srv/lamp/base/libmcrypt/bin:/srv/lamp/base/mcrypt/bin:/srv/lamp/base/onig/bin

WORKDIR /srv/lamp/build

RUN mkdir -p /srv/lamp/build && \
    mkdir -p /srv/lamp/base && \
    cd /srv/lamp/build && \
    # 这里有个坑,如果不安装libxml2-devel,apache make的时候会报一堆apr_util的错,类似下面:
    # /usr/bin/ld: /srv/lamp/apr-util-1.63/lib/libaprutil-1.so: 
    # undefined reference to `XML_SetElementHandler' collect2: error: ld returned 1 exit status
    yum install -y gcc \
    gcc-c++ \
    make wget \
    openssl-devel \
    libxml2-devel && \
    # 下载包
    wget ${expat_source_list} -O ${expat_name}.tar.gz && \
    wget ${apr_source_list} -O ${apr_name}.tar.gz && \
    wget ${apr_util_source_list} -O ${apr_util_name}.tar.gz && \
    wget ${prce_source_list} -O ${prce_name}.tar.gz && \
    wget ${httpd_source_list} -O ${httpd_name}.tar.gz && \
    # 解压源码包
    ls *.tar.gz | xargs -n1 tar xzvf && \
    # 编译apache依赖和Apache
    cd ${expat_name} && \
    ./configure --prefix=/srv/lamp/base/${expat_name} && \
    make -j$(nproc) && \
    make install && \
    cd ../${apr_name} && \
    ./configure --prefix=/srv/lamp/base/${apr_name} && \
    make -j$(nproc) && \
    make install && \
    # 软连接方便后期升级
    ln -s /srv/lamp/base/${apr_name} /srv/lamp/base/apr && \
    cd ../${apr_util_name} && \
    ./configure --prefix=/srv/lamp/base/${apr_util_name}/ --with-apr=/srv/lamp/base/${apr_name} --with-expat=/srv/lamp/base/${expat_name} && \
    make -j$(nproc) && \
    make install && \
    # 软连接方便后期升级
    ln -s /srv/lamp/base/${apr_util_name} /srv/lamp/base/apr-util && \
    cd ../${prce_name}/ && \
    ./configure --prefix=/srv/lamp/base/${prce_name} && \
    make -j$(nproc) && \
    make install && \
    # 软连接方便后期升级
    ln -s /srv/lamp/base/${prce_name} /srv/lamp/base/pcre && \
    cd ../${httpd_name}/ && \
    ./configure --prefix=/srv/lamp/${httpd_name} \
    --sysconfdir=/etc/httpd \
    --enable-so \
    --enable-rewrite \
    --enable-ssl \
    --with-pcre=/srv/lamp/base/${prce_name} \
    --with-apr=/srv/lamp/base/${apr_name} \
    --with-apr-util=/srv/lamp/base/${apr_util_name} \
    --with-expat=builtin && \
    make -j$(nproc) && \
    make install && \
    # 软连接方便后期升级
    ln -s /srv/lamp/${httpd_name} /srv/lamp/apache2 && \
    cd /srv/lamp/build/ && \
    rm -fr /srv/lamp/build/* && \
    # 开始编译php
    yum install -y libxml2 \
    libxml2-devel \
    bzip2-devel \
    perl \
    perl-devel \
    sqlite-devel \
    # 安装zip组件需要的
    libcurl-devel \
    libzip-devel \
    # 安装intl模组需要的
    libicu-devel \
    autoconf \
    # 这个是安装gd模组依赖的
    freetype-devel \
    libpng-devel \
    libjpeg-devel && \
    # 下载包
    wget ${libmcrypt_source_list} -O ${libmcrypt_name}.tar.gz && \
    wget ${mhash_source_list} -O ${mhash_name}.tar.gz && \
    wget ${mcrypt_source_list} -O ${mcrypt_name}.tar.gz && \
    wget ${libiconv_source_list} -O ${libiconv_name}.tar.gz && \
    wget ${oniguruma_source_list} -O ${oniguruma_name}.tar.gz && \
    wget ${php_source_list} -O ${php_name}.tar.gz && \
    # 解压源码包
    ls *.tar.gz | xargs -n1 tar xzvf && \
    # 编译
    # 编译libmcrypt
    cd ${libmcrypt_unpack_name} && \
    chmod +x -R ./ && \
    ./configure --prefix=/srv/lamp/base/${libmcrypt_name} && \
    make -j$(nproc) && \
    make install && \
    ln -s /srv/lamp/base/${libmcrypt_name} /srv/lamp/base/libmcrypt && \
    # 编译mhash
    cd ../${mhash_name} && \
    ./configure --prefix=/srv/lamp/base/${mhash_name} && \
    make -j$(nproc) && \
    make install && \
    ln -s /srv/lamp/base/${mhash_name} /srv/lamp/base/mhash && \
    # 编译mcrypt
    cd ../${mcrypt_name} && \
    export LD_LIBRARY_PATH=/srv/lamp/base/${libmcrypt_name}/lib:/srv/lamp/base/${mhash_name}/lib && \
    export LDFLAGS="-L/srv/lamp/base/${mhash_name}/lib/ -I/srv/lamp/base/${mhash_name}/include/" && \
    export CFLAGS="-I/srv/lamp/base/${mhash_name}/include/" && \
    ./configure --prefix=/srv/lamp/base/${mcrypt_name} --with-libmcrypt-prefix=/srv/lamp/base/${libmcrypt_name} && \
    make -j$(nproc) && \
    make install && \
    ln -s /srv/lamp/base/${mcrypt_name} /srv/lamp/base/mcrypt && \
    # 编译libconv
    cd ../${libiconv_name} && \
    ./configure --prefix=/srv/lamp/base/${libiconv_name} && \
    make -j$(nproc) && \
    make install && \
    # 编译onig
    cd ../${oniguruma_name} && \
    ./configure --prefix=/srv/lamp/base/${oniguruma_name} && \
    make -j$(nproc) && \
    make install && \
    ln -s /srv/lamp/base/${oniguruma_name} /srv/lamp/base/onig && \
    # 编译php
    cd ../${php_name} && \
    ln -s /srv/lamp/base/onig/lib/pkgconfig/oniguruma.pc /usr/lib64/pkgconfig/ && \ 
    sed -i 's#\#!/replace/with/path/to/perl/interpreter -w#\#!/usr/bin/perl -w#' /srv/lamp/apache2/bin/apxs && \
    ./configure --prefix=/srv/lamp/${php_name} \
    --with-openssl \
    --enable-mbstring \
    --with-freetype-dir \
    --with-jpeg-dir \
    --with-png-dir \
    --with-mcrypt \
    --with-zlib \
    # 下面四个不带,如果应用是owncloud,会报错
    --with-zip \
    --with-intl \
    --with-gd \
    --with-curl \
    --with-libxml-dir=/usr \
    --enable-xml  \
    --enable-sockets \
    --with-apxs2=/srv/lamp/apache2/bin/apxs \
    --with-config-file-path=/etc \
    --with-config-file-scan-dir=/etc/php.d \
    --with-bz2  \
    --enable-maintainer-zts \
    --with-iconv=/srv/lamp/base/${libiconv_name} && \
    make -j$(nproc) && \
    make install && \
    ln -s /srv/lamp/${php_name} /srv/lamp/php && \
    EXTLIB_PATH=$(ls -l /srv/lamp/php/lib/php/extensions/ |awk '/^d/ {print "/srv/lamp/php/lib/php/extensions/"$NF}') && \
    # 编译php的intl模组
    cd /srv/lamp/build/${php_name}/ext/intl && \
    phpize && \
    ./configure --enable-intl --with-php-config=/srv/lamp/${php_name}/bin/php-config && \
    make -j$(nproc) && \
    make install && \
    # 默认不生成配置文件,咱们拷贝一个过去
    cp modules/intl.so $EXTLIB_PATH && \
    cd /srv/lamp/build/${php_name} && \
    mv php.ini-production /etc/php.ini && \
    # 写一下配置文件指定动态库地址
    echo "[intl]" >> /etc/php.ini && \
    echo "extension_dir = \"$EXTLIB_PATH\"" >> /etc/php.ini && \
    echo "extension=intl.so" >> /etc/php.ini && \
    # 编译php的gd模组
    cd /srv/lamp/build/${php_name}/ext/gd && \
    phpize && \
    ./configure --with-php-config=/srv/lamp/${php_name}/bin/php-config && \
    make -j$(nproc) && \
    make install && \
    cp modules/gd.so $EXTLIB_PATH && \
    echo "[gd]" >> /etc/php.ini && \
    echo "extension_dir = \"$EXTLIB_PATH\"" >> /etc/php.ini && \
    echo "extension=gd.so" >> /etc/php.ini && \
    # 清理下环境
    yum remove -y gcc \
    gcc-c++ \
    make \
    wget && \
    rm -rf /srv/lamp/build
    
COPY var/www/owncloud /var/www/owncloud
COPY etc/ /etc
COPY usr/bin/entrypoint /usr/bin/entrypoint
COPY var/www/html /var/www/html
COPY mnt /mnt

RUN useradd www-data && \
    chown -R www-data:www-data /var/www && \
    chown -R www-data:www-data /mnt/data && \
    chown -R www-data:www-data /etc/environment && \
    chown -R www-data:www-data /etc/entrypoint.d && \
    mkdir /var/run/apache2 && \
    chown -R www-data:www-data /var/run/apache2/ && \
    rm -fr /var/www/owncloud/config && \
    ln -s /mnt/data/config /var/www/owncloud/config && \
    ln -s /mnt/data/apps /var/www/owncloud/custom

WORKDIR /var/www/owncloud

USER www-data

EXPOSE 8080

ENTRYPOINT [ "/usr/bin/entrypoint" ]