Index: branches/liquidthreads/maintenance/rebuildImages.php |
— | — | @@ -40,8 +40,18 @@ |
41 | 41 | |
42 | 42 | $this->maxLag = 10; # if slaves are lagged more than 10 secs, wait |
43 | 43 | $this->dryrun = $dryrun; |
| 44 | + if ( $dryrun ) { |
| 45 | + $GLOBALS['wgReadOnly'] = 'Dry run mode, image upgrades are suppressed'; |
| 46 | + } |
44 | 47 | } |
45 | 48 | |
| 49 | + function getRepo() { |
| 50 | + if ( !isset( $this->repo ) ) { |
| 51 | + $this->repo = RepoGroup::singleton()->getLocalRepo(); |
| 52 | + } |
| 53 | + return $this->repo; |
| 54 | + } |
| 55 | + |
46 | 56 | function build() { |
47 | 57 | $this->buildImage(); |
48 | 58 | $this->buildOldImage(); |
— | — | @@ -94,13 +104,7 @@ |
95 | 105 | |
96 | 106 | while( $row = $this->dbr->fetchObject( $result ) ) { |
97 | 107 | $update = call_user_func( $callback, $row ); |
98 | | - if( is_array( $update ) ) { |
99 | | - if( !$this->dryrun ) { |
100 | | - $this->dbw->update( $table, |
101 | | - $update, |
102 | | - array( $key => $row->$key ), |
103 | | - $fname ); |
104 | | - } |
| 108 | + if( $update ) { |
105 | 109 | $this->progress( 1 ); |
106 | 110 | } else { |
107 | 111 | $this->progress( 0 ); |
— | — | @@ -116,97 +120,43 @@ |
117 | 121 | } |
118 | 122 | |
119 | 123 | function imageCallback( $row ) { |
120 | | - if( $row->img_width ) { |
121 | | - // Already processed |
122 | | - return null; |
123 | | - } |
124 | | - |
125 | | - // Fill in the new image info fields |
126 | | - $info = $this->imageInfo( $row->img_name ); |
127 | | - |
128 | | - global $wgMemc; |
129 | | - $key = wfMemcKey( "Image", md5( $row->img_name ) ); |
130 | | - $wgMemc->delete( $key ); |
131 | | - |
132 | | - return array( |
133 | | - 'img_width' => $info['width'], |
134 | | - 'img_height' => $info['height'], |
135 | | - 'img_bits' => $info['bits'], |
136 | | - 'img_media_type' => $info['media'], |
137 | | - 'img_major_mime' => $info['major'], |
138 | | - 'img_minor_mime' => $info['minor'] ); |
| 124 | + // Create a File object from the row |
| 125 | + // This will also upgrade it |
| 126 | + $file = $this->getRepo()->newFileFromRow( $row ); |
| 127 | + return $file->getUpgraded(); |
139 | 128 | } |
140 | 129 | |
141 | | - |
142 | 130 | function buildOldImage() { |
143 | 131 | $this->buildTable( 'oldimage', 'oi_archive_name', |
144 | 132 | array( &$this, 'oldimageCallback' ) ); |
145 | 133 | } |
146 | 134 | |
147 | 135 | function oldimageCallback( $row ) { |
148 | | - if( $row->oi_width ) { |
149 | | - return null; |
| 136 | + // Create a File object from the row |
| 137 | + // This will also upgrade it |
| 138 | + if ( $row->oi_archive_name == '' ) { |
| 139 | + $this->log( "Empty oi_archive_name for oi_name={$row->oi_name}" ); |
| 140 | + return false; |
150 | 141 | } |
151 | | - |
152 | | - // Fill in the new image info fields |
153 | | - $info = $this->imageInfo( $row->oi_archive_name, 'wfImageArchiveDir', $row->oi_name ); |
154 | | - return array( |
155 | | - 'oi_width' => $info['width' ], |
156 | | - 'oi_height' => $info['height'], |
157 | | - 'oi_bits' => $info['bits' ] ); |
| 142 | + $file = $this->getRepo()->newFileFromRow( $row ); |
| 143 | + return $file->getUpgraded(); |
158 | 144 | } |
159 | 145 | |
160 | 146 | function crawlMissing() { |
161 | | - global $wgUploadDirectory, $wgHashedUploadDirectory; |
162 | | - if( $wgHashedUploadDirectory ) { |
163 | | - for( $i = 0; $i < 16; $i++ ) { |
164 | | - for( $j = 0; $j < 16; $j++ ) { |
165 | | - $dir = sprintf( '%s%s%01x%s%02x', |
166 | | - $wgUploadDirectory, |
167 | | - DIRECTORY_SEPARATOR, |
168 | | - $i, |
169 | | - DIRECTORY_SEPARATOR, |
170 | | - $i * 16 + $j ); |
171 | | - $this->crawlDirectory( $dir ); |
172 | | - } |
173 | | - } |
174 | | - } else { |
175 | | - $this->crawlDirectory( $wgUploadDirectory ); |
176 | | - } |
| 147 | + $repo = RepoGroup::singleton()->getLocalRepo(); |
| 148 | + $repo->enumFilesInFS( array( $this, 'checkMissingImage' ) ); |
177 | 149 | } |
178 | 150 | |
179 | | - function crawlDirectory( $dir ) { |
180 | | - if( !file_exists( $dir ) ) { |
181 | | - return $this->log( "no directory, skipping $dir" ); |
| 151 | + function checkMissingImage( $fullpath ) { |
| 152 | + $fname = 'ImageBuilder::checkMissingImage'; |
| 153 | + $filename = wfBaseName( $fullpath ); |
| 154 | + if( is_dir( $fullpath ) ) { |
| 155 | + return; |
182 | 156 | } |
183 | | - if( !is_dir( $dir ) ) { |
184 | | - return $this->log( "not a directory?! skipping $dir" ); |
| 157 | + if( is_link( $fullpath ) ) { |
| 158 | + $this->log( "skipping symlink at $fullpath" ); |
| 159 | + return; |
185 | 160 | } |
186 | | - if( !is_readable( $dir ) ) { |
187 | | - return $this->log( "dir not readable, skipping $dir" ); |
188 | | - } |
189 | | - $source = opendir( $dir ); |
190 | | - if( $source === false ) { |
191 | | - return $this->log( "couldn't open dir, skipping $dir" ); |
192 | | - } |
193 | | - |
194 | | - $this->log( "crawling $dir" ); |
195 | | - while( false !== ( $filename = readdir( $source ) ) ) { |
196 | | - $fullpath = $dir . DIRECTORY_SEPARATOR . $filename; |
197 | | - if( is_dir( $fullpath ) ) { |
198 | | - continue; |
199 | | - } |
200 | | - if( is_link( $fullpath ) ) { |
201 | | - $this->log( "skipping symlink at $fullpath" ); |
202 | | - continue; |
203 | | - } |
204 | | - $this->checkMissingImage( $filename, $fullpath ); |
205 | | - } |
206 | | - closedir( $source ); |
207 | | - } |
208 | | - |
209 | | - function checkMissingImage( $filename, $fullpath ) { |
210 | | - $fname = 'ImageBuilder::checkMissingImage'; |
211 | 161 | $row = $this->dbw->selectRow( 'image', |
212 | 162 | array( 'img_name' ), |
213 | 163 | array( 'img_name' => $filename ), |
— | — | @@ -224,7 +174,7 @@ |
225 | 175 | $fname = 'ImageBuilder::addMissingImage'; |
226 | 176 | |
227 | 177 | $size = filesize( $fullpath ); |
228 | | - $info = $this->imageInfo( $filename ); |
| 178 | + $info = $this->imageInfo( $fullpath ); |
229 | 179 | $timestamp = $this->dbw->timestamp( filemtime( $fullpath ) ); |
230 | 180 | |
231 | 181 | global $wgContLang; |
— | — | @@ -242,23 +192,14 @@ |
243 | 193 | $this->log( "Empty filename for $fullpath" ); |
244 | 194 | return; |
245 | 195 | } |
246 | | - |
247 | | - $fields = array( |
248 | | - 'img_name' => $filename, |
249 | | - 'img_size' => $size, |
250 | | - 'img_width' => $info['width'], |
251 | | - 'img_height' => $info['height'], |
252 | | - 'img_metadata' => '', // filled in on-demand |
253 | | - 'img_bits' => $info['bits'], |
254 | | - 'img_media_type' => $info['media'], |
255 | | - 'img_major_mime' => $info['major'], |
256 | | - 'img_minor_mime' => $info['minor'], |
257 | | - 'img_description' => '(recovered file, missing upload log entry)', |
258 | | - 'img_user' => 0, |
259 | | - 'img_user_text' => 'Conversion script', |
260 | | - 'img_timestamp' => $timestamp ); |
261 | | - if( !$this->dryrun ) { |
262 | | - $this->dbw->insert( 'image', $fields, $fname ); |
| 196 | + if ( !$this->dryrun ) { |
| 197 | + $file = wfLocalFile( $filename ); |
| 198 | + if ( !$file->recordUpload( '', '(recovered file, missing upload log entry)', '', '', '', |
| 199 | + false, $timestamp ) ) |
| 200 | + { |
| 201 | + $this->log( "Error uploading file $fullpath" ); |
| 202 | + return; |
| 203 | + } |
263 | 204 | } |
264 | 205 | $this->log( $fullpath ); |
265 | 206 | } |
Index: branches/liquidthreads/maintenance/FiveUpgrade.inc |
— | — | @@ -693,10 +693,7 @@ |
694 | 694 | return $copy; |
695 | 695 | } |
696 | 696 | |
697 | | - function imageInfo( $name, $subdirCallback='wfImageDir', $basename = null ) { |
698 | | - if( is_null( $basename ) ) $basename = $name; |
699 | | - $dir = call_user_func( $subdirCallback, $basename ); |
700 | | - $filename = $dir . '/' . $name; |
| 697 | + function imageInfo( $filename ) { |
701 | 698 | $info = array( |
702 | 699 | 'width' => 0, |
703 | 700 | 'height' => 0, |
— | — | @@ -711,20 +708,13 @@ |
712 | 709 | |
713 | 710 | $info['media'] = $magic->getMediaType( $filename, $mime ); |
714 | 711 | |
715 | | - # Height and width |
716 | | - $gis = false; |
717 | | - if( $mime == 'image/svg' ) { |
718 | | - $gis = wfGetSVGsize( $filename ); |
719 | | - } elseif( $magic->isPHPImageType( $mime ) ) { |
720 | | - $gis = getimagesize( $filename ); |
721 | | - } else { |
722 | | - $this->log( "Surprising mime type: $mime" ); |
723 | | - } |
724 | | - if( $gis ) { |
725 | | - $info['width' ] = $gis[0]; |
726 | | - $info['height'] = $gis[1]; |
727 | | - } |
728 | | - if( isset( $gis['bits'] ) ) { |
| 712 | + $image = UnregisteredLocalFile::newFromPath( $filename, $mime ); |
| 713 | + |
| 714 | + $info['width'] = $image->getWidth(); |
| 715 | + $info['height'] = $image->getHeight(); |
| 716 | + |
| 717 | + $gis = $image->getImageSize(); |
| 718 | + if ( isset( $gis['bits'] ) ) { |
729 | 719 | $info['bits'] = $gis['bits']; |
730 | 720 | } |
731 | 721 | |
— | — | @@ -896,7 +886,7 @@ |
897 | 887 | } |
898 | 888 | |
899 | 889 | function upgradeLogging() { |
900 | | - $tabledef = <<<END |
| 890 | + $tabledef = <<<ENDS |
901 | 891 | CREATE TABLE $1 ( |
902 | 892 | -- Symbolic keys for the general log type and the action type |
903 | 893 | -- within the log. The output format will be controlled by the |
— | — | @@ -926,7 +916,7 @@ |
927 | 917 | KEY page_time (log_namespace, log_title, log_timestamp) |
928 | 918 | |
929 | 919 | ) TYPE=InnoDB |
930 | | -END; |
| 920 | +ENDS; |
931 | 921 | $fields = array( |
932 | 922 | 'log_type' => MW_UPGRADE_COPY, |
933 | 923 | 'log_action' => MW_UPGRADE_COPY, |
— | — | @@ -940,7 +930,7 @@ |
941 | 931 | } |
942 | 932 | |
943 | 933 | function upgradeArchive() { |
944 | | - $tabledef = <<<END |
| 934 | + $tabledef = <<<ENDS |
945 | 935 | CREATE TABLE $1 ( |
946 | 936 | ar_namespace int NOT NULL default '0', |
947 | 937 | ar_title varchar(255) binary NOT NULL default '', |
— | — | @@ -960,7 +950,7 @@ |
961 | 951 | KEY name_title_timestamp (ar_namespace,ar_title,ar_timestamp) |
962 | 952 | |
963 | 953 | ) TYPE=InnoDB |
964 | | -END; |
| 954 | +ENDS; |
965 | 955 | $fields = array( |
966 | 956 | 'ar_namespace' => MW_UPGRADE_COPY, |
967 | 957 | 'ar_title' => MW_UPGRADE_ENCODE, |
— | — | @@ -979,7 +969,7 @@ |
980 | 970 | function upgradeImagelinks() { |
981 | 971 | global $wgUseLatin1; |
982 | 972 | if( $wgUseLatin1 ) { |
983 | | - $tabledef = <<<END |
| 973 | + $tabledef = <<<ENDS |
984 | 974 | CREATE TABLE $1 ( |
985 | 975 | -- Key to page_id of the page containing the image / media link. |
986 | 976 | il_from int(8) unsigned NOT NULL default '0', |
— | — | @@ -993,7 +983,7 @@ |
994 | 984 | KEY (il_to) |
995 | 985 | |
996 | 986 | ) TYPE=InnoDB |
997 | | -END; |
| 987 | +ENDS; |
998 | 988 | $fields = array( |
999 | 989 | 'il_from' => MW_UPGRADE_COPY, |
1000 | 990 | 'il_to' => MW_UPGRADE_ENCODE ); |
— | — | @@ -1004,7 +994,7 @@ |
1005 | 995 | function upgradeCategorylinks() { |
1006 | 996 | global $wgUseLatin1; |
1007 | 997 | if( $wgUseLatin1 ) { |
1008 | | - $tabledef = <<<END |
| 998 | + $tabledef = <<<ENDS |
1009 | 999 | CREATE TABLE $1 ( |
1010 | 1000 | cl_from int(8) unsigned NOT NULL default '0', |
1011 | 1001 | cl_to varchar(255) binary NOT NULL default '', |
— | — | @@ -1015,7 +1005,7 @@ |
1016 | 1006 | KEY cl_sortkey(cl_to,cl_sortkey), |
1017 | 1007 | KEY cl_timestamp(cl_to,cl_timestamp) |
1018 | 1008 | ) TYPE=InnoDB |
1019 | | -END; |
| 1009 | +ENDS; |
1020 | 1010 | $fields = array( |
1021 | 1011 | 'cl_from' => MW_UPGRADE_COPY, |
1022 | 1012 | 'cl_to' => MW_UPGRADE_ENCODE, |
— | — | @@ -1028,7 +1018,7 @@ |
1029 | 1019 | function upgradeIpblocks() { |
1030 | 1020 | global $wgUseLatin1; |
1031 | 1021 | if( $wgUseLatin1 ) { |
1032 | | - $tabledef = <<<END |
| 1022 | + $tabledef = <<<ENDS |
1033 | 1023 | CREATE TABLE $1 ( |
1034 | 1024 | ipb_id int(8) NOT NULL auto_increment, |
1035 | 1025 | ipb_address varchar(40) binary NOT NULL default '', |
— | — | @@ -1044,7 +1034,7 @@ |
1045 | 1035 | INDEX ipb_user (ipb_user) |
1046 | 1036 | |
1047 | 1037 | ) TYPE=InnoDB |
1048 | | -END; |
| 1038 | +ENDS; |
1049 | 1039 | $fields = array( |
1050 | 1040 | 'ipb_id' => MW_UPGRADE_COPY, |
1051 | 1041 | 'ipb_address' => MW_UPGRADE_COPY, |
— | — | @@ -1060,7 +1050,7 @@ |
1061 | 1051 | |
1062 | 1052 | function upgradeRecentchanges() { |
1063 | 1053 | // There's a format change in the namespace field |
1064 | | - $tabledef = <<<END |
| 1054 | + $tabledef = <<<ENDS |
1065 | 1055 | CREATE TABLE $1 ( |
1066 | 1056 | rc_id int(8) NOT NULL auto_increment, |
1067 | 1057 | rc_timestamp varchar(14) binary NOT NULL default '', |
— | — | @@ -1098,7 +1088,7 @@ |
1099 | 1089 | INDEX rc_ip (rc_ip) |
1100 | 1090 | |
1101 | 1091 | ) TYPE=InnoDB |
1102 | | -END; |
| 1092 | +ENDS; |
1103 | 1093 | $fields = array( |
1104 | 1094 | 'rc_id' => MW_UPGRADE_COPY, |
1105 | 1095 | 'rc_timestamp' => MW_UPGRADE_COPY, |
— | — | @@ -1124,7 +1114,7 @@ |
1125 | 1115 | |
1126 | 1116 | function upgradeQuerycache() { |
1127 | 1117 | // There's a format change in the namespace field |
1128 | | - $tabledef = <<<END |
| 1118 | + $tabledef = <<<ENDS |
1129 | 1119 | CREATE TABLE $1 ( |
1130 | 1120 | -- A key name, generally the base name of of the special page. |
1131 | 1121 | qc_type char(32) NOT NULL, |
— | — | @@ -1139,7 +1129,7 @@ |
1140 | 1130 | KEY (qc_type,qc_value) |
1141 | 1131 | |
1142 | 1132 | ) TYPE=InnoDB |
1143 | | -END; |
| 1133 | +ENDS; |
1144 | 1134 | $fields = array( |
1145 | 1135 | 'qc_type' => MW_UPGRADE_COPY, |
1146 | 1136 | 'qc_value' => MW_UPGRADE_COPY, |
Index: branches/liquidthreads/maintenance/importImages.php |
— | — | @@ -42,56 +42,40 @@ |
43 | 43 | $license = isset( $options['license'] ) ? $options['license'] : ''; |
44 | 44 | |
45 | 45 | # Batch "upload" operation |
| 46 | + global $wgUploadDirectory; |
46 | 47 | foreach( $files as $file ) { |
47 | | - |
48 | 48 | $base = wfBaseName( $file ); |
49 | 49 | |
50 | 50 | # Validate a title |
51 | 51 | $title = Title::makeTitleSafe( NS_IMAGE, $base ); |
52 | | - if( is_object( $title ) ) { |
| 52 | + if( !is_object( $title ) ) { |
| 53 | + echo( "{$base} could not be imported; a valid title cannot be produced\n" ); |
| 54 | + continue; |
| 55 | + } |
53 | 56 | |
54 | | - # Check existence |
55 | | - $image = new Image( $title ); |
56 | | - if( !$image->exists() ) { |
| 57 | + # Check existence |
| 58 | + $image = wfLocalFile( $title ); |
| 59 | + if( $image->exists() ) { |
| 60 | + echo( "{$base} could not be imported; a file with this name exists in the wiki\n" ); |
| 61 | + continue; |
| 62 | + } |
57 | 63 | |
58 | | - global $wgUploadDirectory; |
| 64 | + # Stash the file |
| 65 | + echo( "Saving {$base}..." ); |
59 | 66 | |
60 | | - # copy() doesn't create paths so if the hash path doesn't exist, we |
61 | | - # have to create it |
62 | | - makeHashPath( wfGetHashPath( $image->name ) ); |
| 67 | + $archive = $image->publish( $file ); |
| 68 | + if ( WikiError::isError( $archive ) ) { |
| 69 | + echo( "failed.\n" ); |
| 70 | + continue; |
| 71 | + } |
| 72 | + echo( "importing..." ); |
63 | 73 | |
64 | | - # Stash the file |
65 | | - echo( "Saving {$base}..." ); |
66 | | - |
67 | | - if( copy( $file, $image->getFullPath() ) ) { |
68 | | - |
69 | | - echo( "importing..." ); |
70 | | - |
71 | | - # Grab the metadata |
72 | | - $image->loadFromFile(); |
73 | | - |
74 | | - # Record the upload |
75 | | - if( $image->recordUpload( '', $comment, $license ) ) { |
76 | | - |
77 | | - # We're done! |
78 | | - echo( "done.\n" ); |
79 | | - |
80 | | - } else { |
81 | | - echo( "failed.\n" ); |
82 | | - } |
83 | | - |
84 | | - } else { |
85 | | - echo( "failed.\n" ); |
86 | | - } |
87 | | - |
88 | | - } else { |
89 | | - echo( "{$base} could not be imported; a file with this name exists in the wiki\n" ); |
90 | | - } |
91 | | - |
| 74 | + if ( $image->recordUpload( $archive, $comment, $license ) ) { |
| 75 | + # We're done! |
| 76 | + echo( "done.\n" ); |
92 | 77 | } else { |
93 | | - echo( "{$base} could not be imported; a valid title cannot be produced\n" ); |
| 78 | + echo( "failed.\n" ); |
94 | 79 | } |
95 | | - |
96 | 80 | } |
97 | 81 | |
98 | 82 | } else { |
Index: branches/liquidthreads/maintenance/cleanupImages.php |
— | — | @@ -89,7 +89,10 @@ |
90 | 90 | } |
91 | 91 | |
92 | 92 | function filePath( $name ) { |
93 | | - return wfImageDir( $name ) . "/$name"; |
| 93 | + if ( !isset( $this->repo ) ) { |
| 94 | + $this->repo = RepoGroup::singleton()->getLocalRepo(); |
| 95 | + } |
| 96 | + return $this->repo->getRootDirectory() . '/' . $this->repo->getHashPath( $name ) . $name; |
94 | 97 | } |
95 | 98 | |
96 | 99 | function pokeFile( $orig, $new ) { |
Index: branches/liquidthreads/maintenance/importImages.inc.php |
— | — | @@ -47,20 +47,4 @@ |
48 | 48 | return array( $fname, $ext ); |
49 | 49 | } |
50 | 50 | |
51 | | -/** |
52 | | - * Given an image hash, check that the structure exists to save the image file |
53 | | - * and create it if it doesn't |
54 | | - * |
55 | | - * @param $hash Part of an image hash, e.g. /f/fd/ |
56 | | - */ |
57 | | -function makeHashPath( $hash ) { |
58 | | - global $wgUploadDirectory; |
59 | | - $parts = explode( '/', substr( $hash, 1, strlen( $hash ) - 2 ) ); |
60 | | - if( !is_dir( $wgUploadDirectory . '/' . $parts[0] ) ) |
61 | | - mkdir( $wgUploadDirectory . '/' . $parts[0] ); |
62 | | - if( !is_dir( $wgUploadDirectory . '/' . $hash ) ) |
63 | | - mkdir( $wgUploadDirectory . '/' . $hash ); |
64 | | -} |
65 | | - |
66 | | - |
67 | | -?> |
\ No newline at end of file |
| 51 | +?> |
Index: branches/liquidthreads/tests/ImageTest.php |
— | — | @@ -1,67 +0,0 @@ |
2 | | -<?php |
3 | | - |
4 | | -require_once( 'PHPUnit.php' ); |
5 | | -require_once( '../includes/Defines.php' ); |
6 | | -#require_once( '../includes/Profiling.php' ); |
7 | | -require_once( '../includes/GlobalFunctions.php' ); |
8 | | -require_once( '../includes/Image.php' ); |
9 | | -require_once( '../includes/ImageFunctions.php' ); |
10 | | - |
11 | | -class ImageTest extends PHPUnit_TestCase { |
12 | | - function ImageTest( $name ) { |
13 | | - $this->PHPUnit_TestCase( $name ); |
14 | | - } |
15 | | - |
16 | | - function setUp() { |
17 | | - } |
18 | | - |
19 | | - function tearDown() { |
20 | | - } |
21 | | - |
22 | | - function testFitBoxWidth() { |
23 | | - $vals = array( |
24 | | - array( |
25 | | - 'width' => 50, |
26 | | - 'height' => 50, |
27 | | - 'tests' => array( |
28 | | - 50 => 50, |
29 | | - 17 => 17, |
30 | | - 18 => 18 ) ), |
31 | | - array( |
32 | | - 'width' => 366, |
33 | | - 'height' => 300, |
34 | | - 'tests' => array( |
35 | | - 50 => 61, |
36 | | - 17 => 21, |
37 | | - 18 => 22 ) ), |
38 | | - array( |
39 | | - 'width' => 300, |
40 | | - 'height' => 366, |
41 | | - 'tests' => array( |
42 | | - 50 => 41, |
43 | | - 17 => 14, |
44 | | - 18 => 15 ) ), |
45 | | - array( |
46 | | - 'width' => 100, |
47 | | - 'height' => 400, |
48 | | - 'tests' => array( |
49 | | - 50 => 12, |
50 | | - 17 => 4, |
51 | | - 18 => 4 ) ) ); |
52 | | - foreach( $vals as $row ) { |
53 | | - extract( $row ); |
54 | | - foreach( $tests as $max => $expected ) { |
55 | | - $y = round( $expected * $height / $width ); |
56 | | - $result = wfFitBoxWidth( $width, $height, $max ); |
57 | | - $y2 = round( $result * $height / $width ); |
58 | | - $this->assertEquals( $expected, |
59 | | - $result, |
60 | | - "($width, $height, $max) wanted: {$expected}x$y, got: {$result}x$y2" ); |
61 | | - } |
62 | | - } |
63 | | - } |
64 | | - |
65 | | - /* TODO: many more! */ |
66 | | -} |
67 | | - |
68 | | -?> |
Index: branches/liquidthreads/tests/README |
— | — | @@ -1,11 +1,9 @@ |
2 | 2 | Some quickie unit tests done with the PHPUnit testing framework. To run the |
3 | 3 | test suite, run 'make test' in this dir or 'php RunTests.php' |
4 | 4 | |
5 | | -You can install PHPUnit via pear like this: |
6 | | -Firstly, register phpunit channel (it only need to be done once): |
| 5 | +PHPUnit is no longer maintained by PEAR. To get the current version of |
| 6 | +PHPUnit, first uninstall any old version of PHPUnit or PHPUnit2 from PEAR, |
| 7 | +then install the current version from phpunit.de like this: |
| 8 | + |
7 | 9 | # pear channel-discover pear.phpunit.de |
8 | | -Then install the package: |
9 | 10 | # pear install phpunit/PHPUnit |
10 | | - |
11 | | -Or fetch and install it manually: |
12 | | -http://www.phpunit.de/ |
Index: branches/liquidthreads/tests/SanitizerTest.php |
— | — | @@ -1,22 +1,6 @@ |
2 | 2 | <?php |
3 | 3 | |
4 | | -require_once( 'PHPUnit.php' ); |
5 | | -require_once( '../includes/Defines.php' ); |
6 | | -#require_once( '../includes/Profiling.php' ); |
7 | | -require_once( '../includes/GlobalFunctions.php' ); |
8 | | -require_once( '../includes/Sanitizer.php' ); |
9 | | - |
10 | | -class SanitizerTest extends PHPUnit_TestCase { |
11 | | - function SanitizerTest( $name ) { |
12 | | - $this->PHPUnit_TestCase( $name ); |
13 | | - } |
14 | | - |
15 | | - function setUp() { |
16 | | - } |
17 | | - |
18 | | - function tearDown() { |
19 | | - } |
20 | | - |
| 4 | +class SanitizerTest extends PHPUnit_Framework_TestCase { |
21 | 5 | function testDecodeNamed() { |
22 | 6 | $this->assertEquals( |
23 | 7 | "\xc3\xa9cole", |
Index: branches/liquidthreads/tests/ImageFunctionsTest.php |
— | — | @@ -0,0 +1,48 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class ImageFunctionsTest extends PHPUnit_Framework_TestCase { |
| 5 | + function testFitBoxWidth() { |
| 6 | + $vals = array( |
| 7 | + array( |
| 8 | + 'width' => 50, |
| 9 | + 'height' => 50, |
| 10 | + 'tests' => array( |
| 11 | + 50 => 50, |
| 12 | + 17 => 17, |
| 13 | + 18 => 18 ) ), |
| 14 | + array( |
| 15 | + 'width' => 366, |
| 16 | + 'height' => 300, |
| 17 | + 'tests' => array( |
| 18 | + 50 => 61, |
| 19 | + 17 => 21, |
| 20 | + 18 => 22 ) ), |
| 21 | + array( |
| 22 | + 'width' => 300, |
| 23 | + 'height' => 366, |
| 24 | + 'tests' => array( |
| 25 | + 50 => 41, |
| 26 | + 17 => 14, |
| 27 | + 18 => 15 ) ), |
| 28 | + array( |
| 29 | + 'width' => 100, |
| 30 | + 'height' => 400, |
| 31 | + 'tests' => array( |
| 32 | + 50 => 12, |
| 33 | + 17 => 4, |
| 34 | + 18 => 4 ) ) ); |
| 35 | + foreach( $vals as $row ) { |
| 36 | + extract( $row ); |
| 37 | + foreach( $tests as $max => $expected ) { |
| 38 | + $y = round( $expected * $height / $width ); |
| 39 | + $result = wfFitBoxWidth( $width, $height, $max ); |
| 40 | + $y2 = round( $result * $height / $width ); |
| 41 | + $this->assertEquals( $expected, |
| 42 | + $result, |
| 43 | + "($width, $height, $max) wanted: {$expected}x$y, got: {$result}x$y2" ); |
| 44 | + } |
| 45 | + } |
| 46 | + } |
| 47 | +} |
| 48 | + |
| 49 | +?> |
Property changes on: branches/liquidthreads/tests/ImageFunctionsTest.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 50 | + native |
Added: svn:keywords |
2 | 51 | + Author Date Id Revision |
Index: branches/liquidthreads/tests/SearchMySQL4Test.php |
— | — | @@ -1,7 +1,5 @@ |
2 | 2 | <?php |
3 | | - |
4 | 3 | require_once( 'SearchEngineTest.php' ); |
5 | | -require_once( '../includes/SearchMySQL4.php' ); |
6 | 4 | |
7 | 5 | class SearchMySQL4Test extends SearchEngine_TestCase { |
8 | 6 | var $db; |
Index: branches/liquidthreads/tests/run-test.php |
— | — | @@ -0,0 +1,7 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +require_once( dirname(__FILE__) . '/../maintenance/commandLine.inc' ); |
| 5 | +ini_set( 'include_path', get_include_path() . PATH_SEPARATOR . /*$_SERVER['PHP_PEAR_INSTALL_DIR']*/ 'C:\php\pear' ); |
| 6 | +require( 'PHPUnit/TextUI/Command.php' ); |
| 7 | + |
| 8 | +?> |
Property changes on: branches/liquidthreads/tests/run-test.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 9 | + native |
Index: branches/liquidthreads/tests/ArticleTest.php |
— | — | @@ -1,19 +1,8 @@ |
2 | 2 | <?php |
3 | 3 | |
4 | | -require_once( 'PHPUnit.php' ); |
5 | | -require_once( '../includes/Defines.php' ); |
6 | | -require_once( '../includes/Article.php' ); |
7 | | -require_once( '../includes/Revision.php' ); |
8 | | -require_once( '../includes/ProfilerStub.php' ); |
9 | | -require_once( '../includes/normal/UtfNormal.php' ); |
10 | | - |
11 | | -class ArticleTest extends PHPUnit_TestCase { |
| 4 | +class ArticleTest extends PHPUnit_Framework_TestCase { |
12 | 5 | var $saveGlobals = array(); |
13 | 6 | |
14 | | - function ArticleTest( $name ) { |
15 | | - $this->PHPUnit_TestCase( $name ); |
16 | | - } |
17 | | - |
18 | 7 | function setUp() { |
19 | 8 | $globalSet = array( |
20 | 9 | 'wgLegacyEncoding' => false, |
— | — | @@ -104,20 +93,6 @@ |
105 | 94 | Revision::getRevisionText( $row ), "getRevisionText" ); |
106 | 95 | } |
107 | 96 | |
108 | | - function testCompressRevisionTextLatin1() { |
109 | | - $GLOBALS['wgUseLatin1'] = true; |
110 | | - $row->old_text = "Wiki est l'\xe9cole superieur !"; |
111 | | - $row->old_flags = Revision::compressRevisionText( $row->old_text ); |
112 | | - $this->assertFalse( false !== strpos( $row->old_flags, 'utf-8' ), |
113 | | - "Flags should not contain 'utf-8'" ); |
114 | | - $this->assertFalse( false !== strpos( $row->old_flags, 'gzip' ), |
115 | | - "Flags should not contain 'gzip'" ); |
116 | | - $this->assertEquals( "Wiki est l'\xe9cole superieur !", |
117 | | - $row->old_text, "Direct check" ); |
118 | | - $this->assertEquals( "Wiki est l'\xe9cole superieur !", |
119 | | - Revision::getRevisionText( $row ), "getRevisionText" ); |
120 | | - } |
121 | | - |
122 | 97 | function testCompressRevisionTextUtf8Gzip() { |
123 | 98 | $GLOBALS['wgCompressRevisions'] = true; |
124 | 99 | $row->old_text = "Wiki est l'\xc3\xa9cole superieur !"; |
— | — | @@ -131,23 +106,6 @@ |
132 | 107 | $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !", |
133 | 108 | Revision::getRevisionText( $row ), "getRevisionText" ); |
134 | 109 | } |
135 | | - |
136 | | - function testCompressRevisionTextLatin1Gzip() { |
137 | | - $GLOBALS['wgCompressRevisions'] = true; |
138 | | - $GLOBALS['wgUseLatin1'] = true; |
139 | | - $row = new stdClass; |
140 | | - $row->old_text = "Wiki est l'\xe9cole superieur !"; |
141 | | - $row->old_flags = Revision::compressRevisionText( $row->old_text ); |
142 | | - $this->assertFalse( false !== strpos( $row->old_flags, 'utf-8' ), |
143 | | - "Flags should not contain 'utf-8'" ); |
144 | | - $this->assertTrue( false !== strpos( $row->old_flags, 'gzip' ), |
145 | | - "Flags should contain 'gzip'" ); |
146 | | - $this->assertEquals( "Wiki est l'\xe9cole superieur !", |
147 | | - gzinflate( $row->old_text ), "Direct check" ); |
148 | | - $this->assertEquals( "Wiki est l'\xe9cole superieur !", |
149 | | - Revision::getRevisionText( $row ), "getRevisionText" ); |
150 | | - } |
151 | | - |
152 | 110 | } |
153 | 111 | |
154 | 112 | ?> |
Index: branches/liquidthreads/tests/RunTests.php |
— | — | @@ -1,26 +1,12 @@ |
2 | 2 | <?php |
3 | 3 | |
4 | | -if( php_sapi_name() != 'cli' ) { |
5 | | - echo 'Must be run from the command line.'; |
6 | | - die( -1 ); |
7 | | -} |
| 4 | +die( "This is broken, use run-test.php for now.\n" ); |
8 | 5 | |
| 6 | +require_once( dirname( __FILE__ ) . '/../maintenance/commandLine.inc' ); |
| 7 | +ini_set( 'include_path', get_include_path() . PATH_SEPARATOR . /*$_SERVER['PHP_PEAR_INSTALL_DIR']*/ 'C:\php\pear' ); |
9 | 8 | error_reporting( E_ALL ); |
10 | | -define( "MEDIAWIKI", true ); |
| 9 | +require_once( 'PHPUnit/Framework.php' ); |
11 | 10 | |
12 | | -set_include_path( get_include_path() . PATH_SEPARATOR . 'PHPUnit' ); |
13 | | -set_include_path( get_include_path() . PATH_SEPARATOR . '..' ); |
14 | | - |
15 | | -// Error handling when requiring PHPUnit.php |
16 | | -function phpunitErrorHandler( $erno, $errstr, $errfile, $errline) { |
17 | | - echo "Unable to include PHPUnit.php, you should install it first (see README).\n"; |
18 | | - exit(1); |
19 | | -} |
20 | | - |
21 | | -set_error_handler('phpunitErrorHandler'); |
22 | | -require_once( 'PHPUnit.php' ); |
23 | | -restore_error_handler(); |
24 | | - |
25 | 11 | $testOptions = array( |
26 | 12 | 'mysql4' => array( |
27 | 13 | 'server' => null, |
— | — | @@ -34,10 +20,6 @@ |
35 | 21 | 'database' => null ), |
36 | 22 | ); |
37 | 23 | |
38 | | -if( file_exists( 'LocalTestSettings.php' ) ) { |
39 | | - include( './LocalTestSettings.php' ); |
40 | | -} |
41 | | - |
42 | 24 | $tests = array( |
43 | 25 | 'GlobalTest', |
44 | 26 | 'DatabaseTest', |
— | — | @@ -47,14 +29,14 @@ |
48 | 30 | 'ImageTest' |
49 | 31 | ); |
50 | 32 | |
51 | | -if( isset( $_SERVER['argv'][1] ) ) { |
| 33 | +if( count( $args ) ) { |
52 | 34 | // to override... |
53 | | - $tests = array( $_SERVER['argv'][1] ); |
| 35 | + $tests = $args; |
54 | 36 | } |
55 | 37 | |
56 | 38 | foreach( $tests as $test ) { |
57 | 39 | require_once( $test . '.php' ); |
58 | | - $suite = new PHPUnit_TestSuite( $test ); |
| 40 | + $suite = new PHPUnit_Framework_TestSuite( $test ); |
59 | 41 | $result = PHPUnit::run( $suite ); |
60 | 42 | echo $result->toString(); |
61 | 43 | } |
Index: branches/liquidthreads/tests/SearchEngineTest.php |
— | — | @@ -1,20 +1,7 @@ |
2 | 2 | <?php |
3 | 3 | |
4 | | -$IP = '..'; |
5 | | -require_once( 'PHPUnit.php' ); |
6 | | -require_once( '../includes/Defines.php' ); |
7 | | -require_once( '../includes/DefaultSettings.php' ); |
8 | | -#require_once( '../includes/Profiling.php' ); |
9 | | -require_once( '../includes/Hooks.php' ); |
10 | | -require_once( '../includes/MagicWord.php' ); |
11 | | -require_once( '../languages/Language.php' ); |
12 | | - |
13 | | -require_once( '../includes/SearchEngine.php' ); |
14 | | -require_once( '../includes/SearchMySQL.php' ); |
15 | | -require_once( '../includes/SearchMySQL4.php' ); |
16 | | - |
17 | 4 | /** @todo document */ |
18 | | -class SearchEngine_TestCase extends PHPUnit_TestCase { |
| 5 | +class SearchEngine_TestCase extends PHPUnit_Framework_TestCase { |
19 | 6 | var $db, $search; |
20 | 7 | |
21 | 8 | function insertSearchData() { |
Index: branches/liquidthreads/tests/GlobalTest.php |
— | — | @@ -1,32 +1,6 @@ |
2 | 2 | <?php |
3 | 3 | |
4 | | -require_once( 'PHPUnit.php' ); |
5 | | -require_once( '../includes/Defines.php' ); |
6 | | -require_once( '../includes/GlobalFunctions.php' ); |
7 | | -require_once( '../includes/Exception.php' ); |
8 | | - |
9 | | -class GlobalTest extends PHPUnit_TestCase { |
10 | | - function GlobalTest( $name ) { |
11 | | - $this->PHPUnit_TestCase( $name ); |
12 | | - } |
13 | | - |
14 | | - function setUp() { |
15 | | - $this->save = array(); |
16 | | - $saveVars = array( 'wgReadOnlyFile' ); |
17 | | - foreach( $saveVars as $var ) { |
18 | | - if( isset( $GLOBALS[$var] ) ) { |
19 | | - $this->save[$var] = $GLOBALS[$var]; |
20 | | - } |
21 | | - } |
22 | | - $GLOBALS['wgReadOnlyFile'] = wfTempDir() . '/testReadOnly-' . mt_rand(); |
23 | | - } |
24 | | - |
25 | | - function tearDown() { |
26 | | - foreach( $this->save as $var => $data ) { |
27 | | - $GLOBALS[$var] = $data; |
28 | | - } |
29 | | - } |
30 | | - |
| 4 | +class GlobalTest extends PHPUnit_Framework_TestCase { |
31 | 5 | function testRandom() { |
32 | 6 | # This could hypothetically fail, but it shouldn't ;) |
33 | 7 | $this->assertFalse( |
Index: branches/liquidthreads/tests/DatabaseTest.php |
— | — | @@ -1,25 +1,12 @@ |
2 | 2 | <?php |
3 | 3 | |
4 | | -require_once( 'PHPUnit.php' ); |
5 | | -require_once( '../includes/Defines.php' ); |
6 | | -require_once( '../includes/Database.php' ); |
7 | | -require_once( '../includes/GlobalFunctions.php' ); |
8 | | - |
9 | | -class DatabaseTest extends PHPUnit_TestCase { |
| 4 | +class DatabaseTest extends PHPUnit_Framework_TestCase { |
10 | 5 | var $db; |
11 | 6 | |
12 | | - function DatabaseTest( $name ) { |
13 | | - $this->PHPUnit_TestCase( $name ); |
14 | | - } |
15 | | - |
16 | 7 | function setUp() { |
17 | | - $this->db = new Database(); |
| 8 | + $this->db = wfGetDB( DB_SLAVE ); |
18 | 9 | } |
19 | 10 | |
20 | | - function tearDown() { |
21 | | - unset( $this->db ); |
22 | | - } |
23 | | - |
24 | 11 | function testAddQuotesNull() { |
25 | 12 | $this->assertEquals( |
26 | 13 | 'NULL', |
Index: branches/liquidthreads/includes/Image.php |
— | — | @@ -1,2154 +0,0 @@ |
2 | | -<?php |
3 | | -/** |
4 | | - */ |
5 | | - |
6 | | -/** |
7 | | - * NOTE FOR WINDOWS USERS: |
8 | | - * To enable EXIF functions, add the folloing lines to the |
9 | | - * "Windows extensions" section of php.ini: |
10 | | - * |
11 | | - * extension=extensions/php_mbstring.dll |
12 | | - * extension=extensions/php_exif.dll |
13 | | - */ |
14 | | - |
15 | | -/** |
16 | | - * Bump this number when serialized cache records may be incompatible. |
17 | | - */ |
18 | | -define( 'MW_IMAGE_VERSION', 2 ); |
19 | | - |
20 | | -/** |
21 | | - * Class to represent an image |
22 | | - * |
23 | | - * Provides methods to retrieve paths (physical, logical, URL), |
24 | | - * to generate thumbnails or for uploading. |
25 | | - * |
26 | | - * @addtogroup Media |
27 | | - */ |
28 | | -class Image |
29 | | -{ |
30 | | - const DELETED_FILE = 1; |
31 | | - const DELETED_COMMENT = 2; |
32 | | - const DELETED_USER = 4; |
33 | | - const DELETED_RESTRICTED = 8; |
34 | | - const RENDER_NOW = 1; |
35 | | - |
36 | | - /**#@+ |
37 | | - * @private |
38 | | - */ |
39 | | - var $name, # name of the image (constructor) |
40 | | - $imagePath, # Path of the image (loadFromXxx) |
41 | | - $url, # Image URL (accessor) |
42 | | - $title, # Title object for this image (constructor) |
43 | | - $fileExists, # does the image file exist on disk? (loadFromXxx) |
44 | | - $fromSharedDirectory, # load this image from $wgSharedUploadDirectory (loadFromXxx) |
45 | | - $historyLine, # Number of line to return by nextHistoryLine() (constructor) |
46 | | - $historyRes, # result of the query for the image's history (nextHistoryLine) |
47 | | - $width, # \ |
48 | | - $height, # | |
49 | | - $bits, # --- returned by getimagesize (loadFromXxx) |
50 | | - $attr, # / |
51 | | - $type, # MEDIATYPE_xxx (bitmap, drawing, audio...) |
52 | | - $mime, # MIME type, determined by MimeMagic::guessMimeType |
53 | | - $extension, # The file extension (constructor) |
54 | | - $size, # Size in bytes (loadFromXxx) |
55 | | - $metadata, # Metadata |
56 | | - $dataLoaded, # Whether or not all this has been loaded from the database (loadFromXxx) |
57 | | - $page, # Page to render when creating thumbnails |
58 | | - $lastError; # Error string associated with a thumbnail display error |
59 | | - |
60 | | - |
61 | | - /**#@-*/ |
62 | | - |
63 | | - /** |
64 | | - * Create an Image object from an image name |
65 | | - * |
66 | | - * @param string $name name of the image, used to create a title object using Title::makeTitleSafe |
67 | | - * @return Image |
68 | | - * @public |
69 | | - */ |
70 | | - public static function newFromName( $name ) { |
71 | | - $title = Title::makeTitleSafe( NS_IMAGE, $name ); |
72 | | - if ( is_object( $title ) ) { |
73 | | - return new Image( $title ); |
74 | | - } else { |
75 | | - return NULL; |
76 | | - } |
77 | | - } |
78 | | - |
79 | | - /** |
80 | | - * Obsolete factory function, use constructor |
81 | | - * @param Title $title |
82 | | - * @return Image |
83 | | - * @deprecated |
84 | | - */ |
85 | | - function newFromTitle( $title ) { |
86 | | - return new Image( $title ); |
87 | | - } |
88 | | - |
89 | | - /** |
90 | | - * Constructor |
91 | | - * @param Title $title |
92 | | - * @return void |
93 | | - */ |
94 | | - function Image( $title ) { |
95 | | - if( !is_object( $title ) ) { |
96 | | - throw new MWException( 'Image constructor given bogus title.' ); |
97 | | - } |
98 | | - $this->title =& $title; |
99 | | - $this->name = $title->getDBkey(); |
100 | | - $this->metadata = ''; |
101 | | - |
102 | | - $n = strrpos( $this->name, '.' ); |
103 | | - $this->extension = Image::normalizeExtension( $n ? |
104 | | - substr( $this->name, $n + 1 ) : '' ); |
105 | | - $this->historyLine = 0; |
106 | | - |
107 | | - $this->dataLoaded = false; |
108 | | - } |
109 | | - |
110 | | - /** |
111 | | - * Normalize a file extension to the common form, and ensure it's clean. |
112 | | - * Extensions with non-alphanumeric characters will be discarded. |
113 | | - * |
114 | | - * @param string $ext (without the .) |
115 | | - * @return string |
116 | | - */ |
117 | | - static function normalizeExtension( $ext ) { |
118 | | - $lower = strtolower( $ext ); |
119 | | - $squish = array( |
120 | | - 'htm' => 'html', |
121 | | - 'jpeg' => 'jpg', |
122 | | - 'mpeg' => 'mpg', |
123 | | - 'tiff' => 'tif' ); |
124 | | - if( isset( $squish[$lower] ) ) { |
125 | | - return $squish[$lower]; |
126 | | - } elseif( preg_match( '/^[0-9a-z]+$/', $lower ) ) { |
127 | | - return $lower; |
128 | | - } else { |
129 | | - return ''; |
130 | | - } |
131 | | - } |
132 | | - |
133 | | - /** |
134 | | - * Get the memcached keys |
135 | | - * @return array[int]mixed Returns an array, first element is the local cache key, second is the shared cache key, if there is one |
136 | | - */ |
137 | | - function getCacheKeys( ) { |
138 | | - global $wgUseSharedUploads, $wgSharedUploadDBname, $wgCacheSharedUploads; |
139 | | - |
140 | | - $hashedName = md5($this->name); |
141 | | - $keys = array( wfMemcKey( 'Image', $hashedName ) ); |
142 | | - if ( $wgUseSharedUploads && $wgSharedUploadDBname && $wgCacheSharedUploads ) { |
143 | | - $keys[] = wfForeignMemcKey( $wgSharedUploadDBname, false, 'Image', $hashedName ); |
144 | | - } |
145 | | - return $keys; |
146 | | - } |
147 | | - |
148 | | - /** |
149 | | - * Try to load image metadata from memcached. Returns true on success. |
150 | | - */ |
151 | | - function loadFromCache() { |
152 | | - global $wgUseSharedUploads, $wgMemc; |
153 | | - wfProfileIn( __METHOD__ ); |
154 | | - $this->dataLoaded = false; |
155 | | - $keys = $this->getCacheKeys(); |
156 | | - $cachedValues = $wgMemc->get( $keys[0] ); |
157 | | - |
158 | | - // Check if the key existed and belongs to this version of MediaWiki |
159 | | - if (!empty($cachedValues) && is_array($cachedValues) |
160 | | - && isset($cachedValues['version']) && ( $cachedValues['version'] == MW_IMAGE_VERSION ) |
161 | | - && isset( $cachedValues['mime'] ) && isset( $cachedValues['metadata'] ) ) |
162 | | - { |
163 | | - if ( $wgUseSharedUploads && $cachedValues['fromShared']) { |
164 | | - # if this is shared file, we need to check if image |
165 | | - # in shared repository has not changed |
166 | | - if ( isset( $keys[1] ) ) { |
167 | | - $commonsCachedValues = $wgMemc->get( $keys[1] ); |
168 | | - if (!empty($commonsCachedValues) && is_array($commonsCachedValues) |
169 | | - && isset($commonsCachedValues['version']) |
170 | | - && ( $commonsCachedValues['version'] == MW_IMAGE_VERSION ) |
171 | | - && isset($commonsCachedValues['mime'])) { |
172 | | - wfDebug( "Pulling image metadata from shared repository cache\n" ); |
173 | | - $this->name = $commonsCachedValues['name']; |
174 | | - $this->imagePath = $commonsCachedValues['imagePath']; |
175 | | - $this->fileExists = $commonsCachedValues['fileExists']; |
176 | | - $this->width = $commonsCachedValues['width']; |
177 | | - $this->height = $commonsCachedValues['height']; |
178 | | - $this->bits = $commonsCachedValues['bits']; |
179 | | - $this->type = $commonsCachedValues['type']; |
180 | | - $this->mime = $commonsCachedValues['mime']; |
181 | | - $this->metadata = $commonsCachedValues['metadata']; |
182 | | - $this->size = $commonsCachedValues['size']; |
183 | | - $this->fromSharedDirectory = true; |
184 | | - $this->dataLoaded = true; |
185 | | - $this->imagePath = $this->getFullPath(true); |
186 | | - } |
187 | | - } |
188 | | - } else { |
189 | | - wfDebug( "Pulling image metadata from local cache\n" ); |
190 | | - $this->name = $cachedValues['name']; |
191 | | - $this->imagePath = $cachedValues['imagePath']; |
192 | | - $this->fileExists = $cachedValues['fileExists']; |
193 | | - $this->width = $cachedValues['width']; |
194 | | - $this->height = $cachedValues['height']; |
195 | | - $this->bits = $cachedValues['bits']; |
196 | | - $this->type = $cachedValues['type']; |
197 | | - $this->mime = $cachedValues['mime']; |
198 | | - $this->metadata = $cachedValues['metadata']; |
199 | | - $this->size = $cachedValues['size']; |
200 | | - $this->fromSharedDirectory = false; |
201 | | - $this->dataLoaded = true; |
202 | | - $this->imagePath = $this->getFullPath(); |
203 | | - } |
204 | | - } |
205 | | - if ( $this->dataLoaded ) { |
206 | | - wfIncrStats( 'image_cache_hit' ); |
207 | | - } else { |
208 | | - wfIncrStats( 'image_cache_miss' ); |
209 | | - } |
210 | | - |
211 | | - wfProfileOut( __METHOD__ ); |
212 | | - return $this->dataLoaded; |
213 | | - } |
214 | | - |
215 | | - /** |
216 | | - * Save the image metadata to memcached |
217 | | - */ |
218 | | - function saveToCache() { |
219 | | - global $wgMemc, $wgUseSharedUploads; |
220 | | - $this->load(); |
221 | | - $keys = $this->getCacheKeys(); |
222 | | - // We can't cache negative metadata for non-existent files, |
223 | | - // because if the file later appears in commons, the local |
224 | | - // keys won't be purged. |
225 | | - if ( $this->fileExists || !$wgUseSharedUploads ) { |
226 | | - $cachedValues = array( |
227 | | - 'version' => MW_IMAGE_VERSION, |
228 | | - 'name' => $this->name, |
229 | | - 'imagePath' => $this->imagePath, |
230 | | - 'fileExists' => $this->fileExists, |
231 | | - 'fromShared' => $this->fromSharedDirectory, |
232 | | - 'width' => $this->width, |
233 | | - 'height' => $this->height, |
234 | | - 'bits' => $this->bits, |
235 | | - 'type' => $this->type, |
236 | | - 'mime' => $this->mime, |
237 | | - 'metadata' => $this->metadata, |
238 | | - 'size' => $this->size ); |
239 | | - |
240 | | - $wgMemc->set( $keys[0], $cachedValues, 60 * 60 * 24 * 7 ); // A week |
241 | | - } else { |
242 | | - // However we should clear them, so they aren't leftover |
243 | | - // if we've deleted the file. |
244 | | - $wgMemc->delete( $keys[0] ); |
245 | | - } |
246 | | - } |
247 | | - |
248 | | - /** |
249 | | - * Load metadata from the file itself |
250 | | - */ |
251 | | - function loadFromFile() { |
252 | | - global $wgUseSharedUploads, $wgSharedUploadDirectory, $wgContLang; |
253 | | - wfProfileIn( __METHOD__ ); |
254 | | - $this->imagePath = $this->getFullPath(); |
255 | | - $this->fileExists = file_exists( $this->imagePath ); |
256 | | - $this->fromSharedDirectory = false; |
257 | | - $gis = array(); |
258 | | - |
259 | | - if (!$this->fileExists) wfDebug(__METHOD__.': '.$this->imagePath." not found locally!\n"); |
260 | | - |
261 | | - # If the file is not found, and a shared upload directory is used, look for it there. |
262 | | - if (!$this->fileExists && $wgUseSharedUploads && $wgSharedUploadDirectory) { |
263 | | - # In case we're on a wgCapitalLinks=false wiki, we |
264 | | - # capitalize the first letter of the filename before |
265 | | - # looking it up in the shared repository. |
266 | | - $sharedImage = Image::newFromName( $wgContLang->ucfirst($this->name) ); |
267 | | - $this->fileExists = $sharedImage && file_exists( $sharedImage->getFullPath(true) ); |
268 | | - if ( $this->fileExists ) { |
269 | | - $this->name = $sharedImage->name; |
270 | | - $this->imagePath = $this->getFullPath(true); |
271 | | - $this->fromSharedDirectory = true; |
272 | | - } |
273 | | - } |
274 | | - |
275 | | - |
276 | | - if ( $this->fileExists ) { |
277 | | - $magic=& MimeMagic::singleton(); |
278 | | - |
279 | | - $this->mime = $magic->guessMimeType($this->imagePath,true); |
280 | | - $this->type = $magic->getMediaType($this->imagePath,$this->mime); |
281 | | - $handler = MediaHandler::getHandler( $this->mime ); |
282 | | - |
283 | | - # Get size in bytes |
284 | | - $this->size = filesize( $this->imagePath ); |
285 | | - |
286 | | - # Height, width and metadata |
287 | | - if ( $handler ) { |
288 | | - $gis = $handler->getImageSize( $this, $this->imagePath ); |
289 | | - $this->metadata = $handler->getMetadata( $this, $this->imagePath ); |
290 | | - } else { |
291 | | - $gis = false; |
292 | | - $this->metadata = ''; |
293 | | - } |
294 | | - |
295 | | - wfDebug(__METHOD__.': '.$this->imagePath." loaded, ".$this->size." bytes, ".$this->mime.".\n"); |
296 | | - } |
297 | | - else { |
298 | | - $this->mime = NULL; |
299 | | - $this->type = MEDIATYPE_UNKNOWN; |
300 | | - $this->metadata = ''; |
301 | | - wfDebug(__METHOD__.': '.$this->imagePath." NOT FOUND!\n"); |
302 | | - } |
303 | | - |
304 | | - if( $gis ) { |
305 | | - $this->width = $gis[0]; |
306 | | - $this->height = $gis[1]; |
307 | | - } else { |
308 | | - $this->width = 0; |
309 | | - $this->height = 0; |
310 | | - } |
311 | | - |
312 | | - #NOTE: $gis[2] contains a code for the image type. This is no longer used. |
313 | | - |
314 | | - #NOTE: we have to set this flag early to avoid load() to be called |
315 | | - # be some of the functions below. This may lead to recursion or other bad things! |
316 | | - # as ther's only one thread of execution, this should be safe anyway. |
317 | | - $this->dataLoaded = true; |
318 | | - |
319 | | - if ( isset( $gis['bits'] ) ) $this->bits = $gis['bits']; |
320 | | - else $this->bits = 0; |
321 | | - |
322 | | - wfProfileOut( __METHOD__ ); |
323 | | - } |
324 | | - |
325 | | - /** |
326 | | - * Load image metadata from the DB |
327 | | - */ |
328 | | - function loadFromDB() { |
329 | | - global $wgUseSharedUploads, $wgSharedUploadDBname, $wgSharedUploadDBprefix, $wgContLang; |
330 | | - wfProfileIn( __METHOD__ ); |
331 | | - |
332 | | - $dbr = wfGetDB( DB_SLAVE ); |
333 | | - |
334 | | - $row = $dbr->selectRow( 'image', |
335 | | - array( 'img_size', 'img_width', 'img_height', 'img_bits', |
336 | | - 'img_media_type', 'img_major_mime', 'img_minor_mime', 'img_metadata' ), |
337 | | - array( 'img_name' => $this->name ), __METHOD__ ); |
338 | | - if ( $row ) { |
339 | | - $this->fromSharedDirectory = false; |
340 | | - $this->fileExists = true; |
341 | | - $this->loadFromRow( $row ); |
342 | | - $this->imagePath = $this->getFullPath(); |
343 | | - // Check for rows from a previous schema, quietly upgrade them |
344 | | - $this->maybeUpgradeRow(); |
345 | | - } elseif ( $wgUseSharedUploads && $wgSharedUploadDBname ) { |
346 | | - # In case we're on a wgCapitalLinks=false wiki, we |
347 | | - # capitalize the first letter of the filename before |
348 | | - # looking it up in the shared repository. |
349 | | - $name = $wgContLang->ucfirst($this->name); |
350 | | - $dbc = Image::getCommonsDB(); |
351 | | - |
352 | | - $row = $dbc->selectRow( "`$wgSharedUploadDBname`.{$wgSharedUploadDBprefix}image", |
353 | | - array( |
354 | | - 'img_size', 'img_width', 'img_height', 'img_bits', |
355 | | - 'img_media_type', 'img_major_mime', 'img_minor_mime', 'img_metadata' ), |
356 | | - array( 'img_name' => $name ), __METHOD__ ); |
357 | | - if ( $row ) { |
358 | | - $this->fromSharedDirectory = true; |
359 | | - $this->fileExists = true; |
360 | | - $this->imagePath = $this->getFullPath(true); |
361 | | - $this->name = $name; |
362 | | - $this->loadFromRow( $row ); |
363 | | - |
364 | | - // Check for rows from a previous schema, quietly upgrade them |
365 | | - $this->maybeUpgradeRow(); |
366 | | - } |
367 | | - } |
368 | | - |
369 | | - if ( !$row ) { |
370 | | - $this->size = 0; |
371 | | - $this->width = 0; |
372 | | - $this->height = 0; |
373 | | - $this->bits = 0; |
374 | | - $this->type = 0; |
375 | | - $this->fileExists = false; |
376 | | - $this->fromSharedDirectory = false; |
377 | | - $this->metadata = ''; |
378 | | - $this->mime = false; |
379 | | - } |
380 | | - |
381 | | - # Unconditionally set loaded=true, we don't want the accessors constantly rechecking |
382 | | - $this->dataLoaded = true; |
383 | | - wfProfileOut( __METHOD__ ); |
384 | | - } |
385 | | - |
386 | | - /* |
387 | | - * Load image metadata from a DB result row |
388 | | - */ |
389 | | - function loadFromRow( &$row ) { |
390 | | - $this->size = $row->img_size; |
391 | | - $this->width = $row->img_width; |
392 | | - $this->height = $row->img_height; |
393 | | - $this->bits = $row->img_bits; |
394 | | - $this->type = $row->img_media_type; |
395 | | - |
396 | | - $major= $row->img_major_mime; |
397 | | - $minor= $row->img_minor_mime; |
398 | | - |
399 | | - if (!$major) $this->mime = "unknown/unknown"; |
400 | | - else { |
401 | | - if (!$minor) $minor= "unknown"; |
402 | | - $this->mime = $major.'/'.$minor; |
403 | | - } |
404 | | - $this->metadata = $row->img_metadata; |
405 | | - |
406 | | - $this->dataLoaded = true; |
407 | | - } |
408 | | - |
409 | | - /** |
410 | | - * Load image metadata from cache or DB, unless already loaded |
411 | | - */ |
412 | | - function load() { |
413 | | - global $wgSharedUploadDBname, $wgUseSharedUploads; |
414 | | - if ( !$this->dataLoaded ) { |
415 | | - if ( !$this->loadFromCache() ) { |
416 | | - $this->loadFromDB(); |
417 | | - if ( !$wgSharedUploadDBname && $wgUseSharedUploads ) { |
418 | | - $this->loadFromFile(); |
419 | | - } elseif ( $this->fileExists || !$wgUseSharedUploads ) { |
420 | | - // We can do negative caching for local images, because the cache |
421 | | - // will be purged on upload. But we can't do it when shared images |
422 | | - // are enabled, since updates to that won't purge foreign caches. |
423 | | - $this->saveToCache(); |
424 | | - } |
425 | | - } |
426 | | - $this->dataLoaded = true; |
427 | | - } |
428 | | - } |
429 | | - |
430 | | - /** |
431 | | - * Upgrade a row if it needs it |
432 | | - * @return void |
433 | | - */ |
434 | | - function maybeUpgradeRow() { |
435 | | - if ( is_null($this->type) || $this->mime == 'image/svg' ) { |
436 | | - $this->upgradeRow(); |
437 | | - } else { |
438 | | - $handler = $this->getHandler(); |
439 | | - if ( $handler && !$handler->isMetadataValid( $this, $this->metadata ) ) { |
440 | | - $this->upgradeRow(); |
441 | | - } |
442 | | - } |
443 | | - } |
444 | | - |
445 | | - /** |
446 | | - * Fix assorted version-related problems with the image row by reloading it from the file |
447 | | - */ |
448 | | - function upgradeRow() { |
449 | | - global $wgDBname, $wgSharedUploadDBname; |
450 | | - wfProfileIn( __METHOD__ ); |
451 | | - |
452 | | - $this->loadFromFile(); |
453 | | - |
454 | | - if ( $this->fromSharedDirectory ) { |
455 | | - if ( !$wgSharedUploadDBname ) { |
456 | | - wfProfileOut( __METHOD__ ); |
457 | | - return; |
458 | | - } |
459 | | - |
460 | | - // Write to the other DB using selectDB, not database selectors |
461 | | - // This avoids breaking replication in MySQL |
462 | | - $dbw = Image::getCommonsDB(); |
463 | | - } else { |
464 | | - $dbw = wfGetDB( DB_MASTER ); |
465 | | - } |
466 | | - |
467 | | - list( $major, $minor ) = self::splitMime( $this->mime ); |
468 | | - |
469 | | - wfDebug(__METHOD__.': upgrading '.$this->name." to the current schema\n"); |
470 | | - |
471 | | - $dbw->update( 'image', |
472 | | - array( |
473 | | - 'img_width' => $this->width, |
474 | | - 'img_height' => $this->height, |
475 | | - 'img_bits' => $this->bits, |
476 | | - 'img_media_type' => $this->type, |
477 | | - 'img_major_mime' => $major, |
478 | | - 'img_minor_mime' => $minor, |
479 | | - 'img_metadata' => $this->metadata, |
480 | | - ), array( 'img_name' => $this->name ), __METHOD__ |
481 | | - ); |
482 | | - if ( $this->fromSharedDirectory ) { |
483 | | - $dbw->selectDB( $wgDBname ); |
484 | | - } |
485 | | - wfProfileOut( __METHOD__ ); |
486 | | - } |
487 | | - |
488 | | - /** |
489 | | - * Split an internet media type into its two components; if not |
490 | | - * a two-part name, set the minor type to 'unknown'. |
491 | | - * |
492 | | - * @param string $mime "text/html" etc |
493 | | - * @return array ("text", "html") etc |
494 | | - */ |
495 | | - static function splitMime( $mime ) { |
496 | | - if( strpos( $mime, '/' ) !== false ) { |
497 | | - return explode( '/', $mime, 2 ); |
498 | | - } else { |
499 | | - return array( $mime, 'unknown' ); |
500 | | - } |
501 | | - } |
502 | | - |
503 | | - /** |
504 | | - * Return the name of this image |
505 | | - * @public |
506 | | - */ |
507 | | - function getName() { |
508 | | - return $this->name; |
509 | | - } |
510 | | - |
511 | | - /** |
512 | | - * Return the associated title object |
513 | | - * @public |
514 | | - */ |
515 | | - function getTitle() { |
516 | | - return $this->title; |
517 | | - } |
518 | | - |
519 | | - /** |
520 | | - * Return the URL of the image file |
521 | | - * @public |
522 | | - */ |
523 | | - function getURL() { |
524 | | - if ( !$this->url ) { |
525 | | - $this->load(); |
526 | | - if($this->fileExists) { |
527 | | - $this->url = Image::imageUrl( $this->name, $this->fromSharedDirectory ); |
528 | | - } else { |
529 | | - $this->url = ''; |
530 | | - } |
531 | | - } |
532 | | - return $this->url; |
533 | | - } |
534 | | - |
535 | | - function getViewURL() { |
536 | | - if( $this->mustRender()) { |
537 | | - if( $this->canRender() ) { |
538 | | - return $this->createThumb( $this->getWidth() ); |
539 | | - } |
540 | | - else { |
541 | | - wfDebug('Image::getViewURL(): supposed to render '.$this->name.' ('.$this->mime."), but can't!\n"); |
542 | | - return $this->getURL(); #hm... return NULL? |
543 | | - } |
544 | | - } else { |
545 | | - return $this->getURL(); |
546 | | - } |
547 | | - } |
548 | | - |
549 | | - /** |
550 | | - * Return the image path of the image in the |
551 | | - * local file system as an absolute path |
552 | | - * @public |
553 | | - */ |
554 | | - function getImagePath() { |
555 | | - $this->load(); |
556 | | - return $this->imagePath; |
557 | | - } |
558 | | - |
559 | | - /** |
560 | | - * @return mixed Return the width of the image; returns false on error. |
561 | | - * @param int $page Page number to find the width of. |
562 | | - * @public |
563 | | - */ |
564 | | - function getWidth( $page = 1 ) { |
565 | | - $this->load(); |
566 | | - if ( $this->isMultipage() ) { |
567 | | - $dim = $this->getHandler()->getPageDimensions( $this, $page ); |
568 | | - if ( $dim ) { |
569 | | - return $dim['width']; |
570 | | - } else { |
571 | | - return false; |
572 | | - } |
573 | | - } else { |
574 | | - return $this->width; |
575 | | - } |
576 | | - } |
577 | | - |
578 | | - /** |
579 | | - * @return mixed Return the height of the image; Returns false on error. |
580 | | - * @param int $page Page number to find the height of. |
581 | | - * @public |
582 | | - */ |
583 | | - function getHeight( $page = 1 ) { |
584 | | - $this->load(); |
585 | | - if ( $this->isMultipage() ) { |
586 | | - $dim = $this->getHandler()->getPageDimensions( $this, $page ); |
587 | | - if ( $dim ) { |
588 | | - return $dim['height']; |
589 | | - } else { |
590 | | - return false; |
591 | | - } |
592 | | - } else { |
593 | | - return $this->height; |
594 | | - } |
595 | | - } |
596 | | - |
597 | | - /** |
598 | | - * Get handler-specific metadata |
599 | | - */ |
600 | | - function getMetadata() { |
601 | | - $this->load(); |
602 | | - return $this->metadata; |
603 | | - } |
604 | | - |
605 | | - /** |
606 | | - * @return int the size of the image file, in bytes |
607 | | - * @public |
608 | | - */ |
609 | | - function getSize() { |
610 | | - $this->load(); |
611 | | - return $this->size; |
612 | | - } |
613 | | - |
614 | | - /** |
615 | | - * @return string the mime type of the file. |
616 | | - */ |
617 | | - function getMimeType() { |
618 | | - $this->load(); |
619 | | - return $this->mime; |
620 | | - } |
621 | | - |
622 | | - /** |
623 | | - * Return the type of the media in the file. |
624 | | - * Use the value returned by this function with the MEDIATYPE_xxx constants. |
625 | | - */ |
626 | | - function getMediaType() { |
627 | | - $this->load(); |
628 | | - return $this->type; |
629 | | - } |
630 | | - |
631 | | - /** |
632 | | - * Checks if the file can be presented to the browser as a bitmap. |
633 | | - * |
634 | | - * Currently, this checks if the file is an image format |
635 | | - * that can be converted to a format |
636 | | - * supported by all browsers (namely GIF, PNG and JPEG), |
637 | | - * or if it is an SVG image and SVG conversion is enabled. |
638 | | - * |
639 | | - * @todo remember the result of this check. |
640 | | - * @return boolean |
641 | | - */ |
642 | | - function canRender() { |
643 | | - $handler = $this->getHandler(); |
644 | | - return $handler && $handler->canRender(); |
645 | | - } |
646 | | - |
647 | | - /** |
648 | | - * Return true if the file is of a type that can't be directly |
649 | | - * rendered by typical browsers and needs to be re-rasterized. |
650 | | - * |
651 | | - * This returns true for everything but the bitmap types |
652 | | - * supported by all browsers, i.e. JPEG; GIF and PNG. It will |
653 | | - * also return true for any non-image formats. |
654 | | - * |
655 | | - * @return bool |
656 | | - */ |
657 | | - function mustRender() { |
658 | | - $handler = $this->getHandler(); |
659 | | - return $handler && $handler->mustRender(); |
660 | | - } |
661 | | - |
662 | | - /** |
663 | | - * Determines if this media file may be shown inline on a page. |
664 | | - * |
665 | | - * This is currently synonymous to canRender(), but this could be |
666 | | - * extended to also allow inline display of other media, |
667 | | - * like flash animations or videos. If you do so, please keep in mind that |
668 | | - * that could be a security risk. |
669 | | - */ |
670 | | - function allowInlineDisplay() { |
671 | | - return $this->canRender(); |
672 | | - } |
673 | | - |
674 | | - /** |
675 | | - * Determines if this media file is in a format that is unlikely to |
676 | | - * contain viruses or malicious content. It uses the global |
677 | | - * $wgTrustedMediaFormats list to determine if the file is safe. |
678 | | - * |
679 | | - * This is used to show a warning on the description page of non-safe files. |
680 | | - * It may also be used to disallow direct [[media:...]] links to such files. |
681 | | - * |
682 | | - * Note that this function will always return true if allowInlineDisplay() |
683 | | - * or isTrustedFile() is true for this file. |
684 | | - * |
685 | | - * @return boolean |
686 | | - */ |
687 | | - function isSafeFile() { |
688 | | - if ($this->allowInlineDisplay()) return true; |
689 | | - if ($this->isTrustedFile()) return true; |
690 | | - |
691 | | - global $wgTrustedMediaFormats; |
692 | | - |
693 | | - $type= $this->getMediaType(); |
694 | | - $mime= $this->getMimeType(); |
695 | | - #wfDebug("Image::isSafeFile: type= $type, mime= $mime\n"); |
696 | | - |
697 | | - if (!$type || $type===MEDIATYPE_UNKNOWN) return false; #unknown type, not trusted |
698 | | - if ( in_array( $type, $wgTrustedMediaFormats) ) return true; |
699 | | - |
700 | | - if ($mime==="unknown/unknown") return false; #unknown type, not trusted |
701 | | - if ( in_array( $mime, $wgTrustedMediaFormats) ) return true; |
702 | | - |
703 | | - return false; |
704 | | - } |
705 | | - |
706 | | - /** |
707 | | - * Returns true if the file is flagged as trusted. Files flagged that way |
708 | | - * can be linked to directly, even if that is not allowed for this type of |
709 | | - * file normally. |
710 | | - * |
711 | | - * This is a dummy function right now and always returns false. It could be |
712 | | - * implemented to extract a flag from the database. The trusted flag could be |
713 | | - * set on upload, if the user has sufficient privileges, to bypass script- |
714 | | - * and html-filters. It may even be coupled with cryptographics signatures |
715 | | - * or such. |
716 | | - * @return boolean |
717 | | - */ |
718 | | - function isTrustedFile() { |
719 | | - #this could be implemented to check a flag in the database, |
720 | | - #look for signatures, etc |
721 | | - return false; |
722 | | - } |
723 | | - |
724 | | - /** |
725 | | - * Return the escapeLocalURL of this image |
726 | | - * @param string $query URL query string |
727 | | - * @public |
728 | | - */ |
729 | | - function getEscapeLocalURL( $query=false) { |
730 | | - return $this->getTitle()->escapeLocalURL( $query ); |
731 | | - } |
732 | | - |
733 | | - /** |
734 | | - * Return the escapeFullURL of this image |
735 | | - * @public |
736 | | - */ |
737 | | - function getEscapeFullURL() { |
738 | | - $this->getTitle(); |
739 | | - return $this->title->escapeFullURL(); |
740 | | - } |
741 | | - |
742 | | - /** |
743 | | - * Return the URL of an image, provided its name. |
744 | | - * |
745 | | - * @param string $name Name of the image, without the leading "Image:" |
746 | | - * @param boolean $fromSharedDirectory Should this be in $wgSharedUploadPath? |
747 | | - * @return string URL of $name image |
748 | | - * @public |
749 | | - */ |
750 | | - static function imageUrl( $name, $fromSharedDirectory = false ) { |
751 | | - global $wgUploadPath,$wgUploadBaseUrl,$wgSharedUploadPath; |
752 | | - if($fromSharedDirectory) { |
753 | | - $base = ''; |
754 | | - $path = $wgSharedUploadPath; |
755 | | - } else { |
756 | | - $base = $wgUploadBaseUrl; |
757 | | - $path = $wgUploadPath; |
758 | | - } |
759 | | - $url = "{$base}{$path}" . wfGetHashPath($name, $fromSharedDirectory) . "{$name}"; |
760 | | - return wfUrlencode( $url ); |
761 | | - } |
762 | | - |
763 | | - /** |
764 | | - * Returns true if the image file exists on disk. |
765 | | - * @return boolean Whether image file exist on disk. |
766 | | - * @public |
767 | | - */ |
768 | | - function exists() { |
769 | | - $this->load(); |
770 | | - return $this->fileExists; |
771 | | - } |
772 | | - |
773 | | - /** |
774 | | - * @todo document |
775 | | - * @param string $thumbName |
776 | | - * @param string $subdir |
777 | | - * @return string |
778 | | - * @private |
779 | | - */ |
780 | | - function thumbUrlFromName( $thumbName, $subdir = 'thumb' ) { |
781 | | - global $wgUploadPath, $wgUploadBaseUrl, $wgSharedUploadPath; |
782 | | - if($this->fromSharedDirectory) { |
783 | | - $base = ''; |
784 | | - $path = $wgSharedUploadPath; |
785 | | - } else { |
786 | | - $base = $wgUploadBaseUrl; |
787 | | - $path = $wgUploadPath; |
788 | | - } |
789 | | - if ( Image::isHashed( $this->fromSharedDirectory ) ) { |
790 | | - $hashdir = wfGetHashPath($this->name, $this->fromSharedDirectory) . |
791 | | - wfUrlencode( $this->name ); |
792 | | - } else { |
793 | | - $hashdir = ''; |
794 | | - } |
795 | | - $url = "{$base}{$path}/{$subdir}{$hashdir}/" . wfUrlencode( $thumbName ); |
796 | | - return $url; |
797 | | - } |
798 | | - |
799 | | - /** |
800 | | - * @deprecated Use $image->transform()->getUrl() or thumbUrlFromName() |
801 | | - */ |
802 | | - function thumbUrl( $width, $subdir = 'thumb' ) { |
803 | | - $name = $this->thumbName( array( 'width' => $width ) ); |
804 | | - if ( strval( $name ) !== '' ) { |
805 | | - return array( false, $this->thumbUrlFromName( $name, $subdir ) ); |
806 | | - } else { |
807 | | - return array( false, false ); |
808 | | - } |
809 | | - } |
810 | | - |
811 | | - /** |
812 | | - * @return mixed |
813 | | - */ |
814 | | - function getTransformScript() { |
815 | | - global $wgSharedThumbnailScriptPath, $wgThumbnailScriptPath; |
816 | | - if ( $this->fromSharedDirectory ) { |
817 | | - $script = $wgSharedThumbnailScriptPath; |
818 | | - } else { |
819 | | - $script = $wgThumbnailScriptPath; |
820 | | - } |
821 | | - if ( $script ) { |
822 | | - return "$script?f=" . urlencode( $this->name ); |
823 | | - } else { |
824 | | - return false; |
825 | | - } |
826 | | - } |
827 | | - |
828 | | - /** |
829 | | - * Get a ThumbnailImage which is the same size as the source |
830 | | - * @param mixed $page |
831 | | - * @return MediaTransformOutput |
832 | | - */ |
833 | | - function getUnscaledThumb( $page = false ) { |
834 | | - if ( $page ) { |
835 | | - $params = array( |
836 | | - 'page' => $page, |
837 | | - 'width' => $this->getWidth( $page ) |
838 | | - ); |
839 | | - } else { |
840 | | - $params = array( 'width' => $this->getWidth() ); |
841 | | - } |
842 | | - return $this->transform( $params ); |
843 | | - } |
844 | | - |
845 | | - /** |
846 | | - * Return the file name of a thumbnail with the specified parameters |
847 | | - * |
848 | | - * @param array $params Handler-specific parameters |
849 | | - * @return string file name of a thumbnail with the specified parameters |
850 | | - * @private |
851 | | - */ |
852 | | - function thumbName( $params ) { |
853 | | - $handler = $this->getHandler(); |
854 | | - if ( !$handler ) { |
855 | | - return null; |
856 | | - } |
857 | | - list( $thumbExt, /* $thumbMime */ ) = self::getThumbType( $this->extension, $this->mime ); |
858 | | - $thumbName = $handler->makeParamString( $params ) . '-' . $this->name; |
859 | | - if ( $thumbExt != $this->extension ) { |
860 | | - $thumbName .= ".$thumbExt"; |
861 | | - } |
862 | | - return $thumbName; |
863 | | - } |
864 | | - |
865 | | - /** |
866 | | - * Create a thumbnail of the image having the specified width/height. |
867 | | - * The thumbnail will not be created if the width is larger than the |
868 | | - * image's width. Let the browser do the scaling in this case. |
869 | | - * The thumbnail is stored on disk and is only computed if the thumbnail |
870 | | - * file does not exist OR if it is older than the image. |
871 | | - * Returns the URL. |
872 | | - * |
873 | | - * Keeps aspect ratio of original image. If both width and height are |
874 | | - * specified, the generated image will be no bigger than width x height, |
875 | | - * and will also have correct aspect ratio. |
876 | | - * |
877 | | - * @param integer $width maximum width of the generated thumbnail |
878 | | - * @param integer $height maximum height of the image (optional) |
879 | | - * @public |
880 | | - */ |
881 | | - function createThumb( $width, $height = -1 ) { |
882 | | - $params = array( 'width' => $width ); |
883 | | - if ( $height != -1 ) { |
884 | | - $params['height'] = $height; |
885 | | - } |
886 | | - $thumb = $this->transform( $params ); |
887 | | - if( is_null( $thumb ) || $thumb->isError() ) return ''; |
888 | | - return $thumb->getUrl(); |
889 | | - } |
890 | | - |
891 | | - /** |
892 | | - * As createThumb, but returns a ThumbnailImage object. This can |
893 | | - * provide access to the actual file, the real size of the thumb, |
894 | | - * and can produce a convenient <img> tag for you. |
895 | | - * |
896 | | - * For non-image formats, this may return a filetype-specific icon. |
897 | | - * |
898 | | - * @param integer $width maximum width of the generated thumbnail |
899 | | - * @param integer $height maximum height of the image (optional) |
900 | | - * @param boolean $render True to render the thumbnail if it doesn't exist, |
901 | | - * false to just return the URL |
902 | | - * |
903 | | - * @return ThumbnailImage or null on failure |
904 | | - * @public |
905 | | - * |
906 | | - * @deprecated use transform() |
907 | | - */ |
908 | | - function getThumbnail( $width, $height=-1, $render = true ) { |
909 | | - $params = array( 'width' => $width ); |
910 | | - if ( $height != -1 ) { |
911 | | - $params['height'] = $height; |
912 | | - } |
913 | | - $flags = $render ? self::RENDER_NOW : 0; |
914 | | - return $this->transform( $params, $flags ); |
915 | | - } |
916 | | - |
917 | | - /** |
918 | | - * Transform a media file |
919 | | - * |
920 | | - * @param array[string]mixed $params An associative array of handler-specific parameters. |
921 | | - * Typical keys are width, height and page. |
922 | | - * @param integer $flags A bitfield, may contain self::RENDER_NOW to force rendering |
923 | | - * @return MediaTransformOutput |
924 | | - */ |
925 | | - function transform( $params, $flags = 0 ) { |
926 | | - global $wgGenerateThumbnailOnParse, $wgUseSquid, $wgIgnoreImageErrors; |
927 | | - |
928 | | - wfProfileIn( __METHOD__ ); |
929 | | - do { |
930 | | - $handler = $this->getHandler(); |
931 | | - if ( !$handler || !$handler->canRender() ) { |
932 | | - // not a bitmap or renderable image, don't try. |
933 | | - $thumb = $this->iconThumb(); |
934 | | - break; |
935 | | - } |
936 | | - |
937 | | - $script = $this->getTransformScript(); |
938 | | - if ( $script && !($flags & self::RENDER_NOW) ) { |
939 | | - // Use a script to transform on client request |
940 | | - $thumb = $handler->getScriptedTransform( $this, $script, $params ); |
941 | | - break; |
942 | | - } |
943 | | - |
944 | | - $normalisedParams = $params; |
945 | | - $handler->normaliseParams( $this, $normalisedParams ); |
946 | | - $thumbName = $this->thumbName( $normalisedParams ); |
947 | | - $thumbPath = wfImageThumbDir( $this->name, $this->fromSharedDirectory ) . "/$thumbName"; |
948 | | - $thumbUrl = $this->thumbUrlFromName( $thumbName ); |
949 | | - |
950 | | - |
951 | | - if ( !$wgGenerateThumbnailOnParse && !($flags & self::RENDER_NOW ) ) { |
952 | | - $thumb = $handler->getTransform( $this, $thumbPath, $thumbUrl, $params ); |
953 | | - break; |
954 | | - } |
955 | | - |
956 | | - wfDebug( "Doing stat for $thumbPath\n" ); |
957 | | - $this->migrateThumbFile( $thumbName ); |
958 | | - if ( file_exists( $thumbPath ) ) { |
959 | | - $thumb = $handler->getTransform( $this, $thumbPath, $thumbUrl, $params ); |
960 | | - break; |
961 | | - } |
962 | | - |
963 | | - $thumb = $handler->doTransform( $this, $thumbPath, $thumbUrl, $params ); |
964 | | - |
965 | | - // Ignore errors if requested |
966 | | - if ( !$thumb ) { |
967 | | - $thumb = null; |
968 | | - } elseif ( $thumb->isError() ) { |
969 | | - $this->lastError = $thumb->toText(); |
970 | | - if ( $wgIgnoreImageErrors && !($flags & self::RENDER_NOW) ) { |
971 | | - $thumb = $handler->getTransform( $this, $thumbPath, $thumbUrl, $params ); |
972 | | - } |
973 | | - } |
974 | | - |
975 | | - if ( $wgUseSquid ) { |
976 | | - wfPurgeSquidServers( array( $thumbUrl ) ); |
977 | | - } |
978 | | - } while (false); |
979 | | - |
980 | | - wfProfileOut( __METHOD__ ); |
981 | | - return $thumb; |
982 | | - } |
983 | | - |
984 | | - /** |
985 | | - * Fix thumbnail files from 1.4 or before, with extreme prejudice |
986 | | - * @param string $thumbName File name of thumbnail. |
987 | | - * @return void |
988 | | - */ |
989 | | - function migrateThumbFile( $thumbName ) { |
990 | | - $thumbDir = wfImageThumbDir( $this->name, $this->fromSharedDirectory ); |
991 | | - $thumbPath = "$thumbDir/$thumbName"; |
992 | | - if ( is_dir( $thumbPath ) ) { |
993 | | - // Directory where file should be |
994 | | - // This happened occasionally due to broken migration code in 1.5 |
995 | | - // Rename to broken-* |
996 | | - global $wgUploadDirectory; |
997 | | - for ( $i = 0; $i < 100 ; $i++ ) { |
998 | | - $broken = "$wgUploadDirectory/broken-$i-$thumbName"; |
999 | | - if ( !file_exists( $broken ) ) { |
1000 | | - rename( $thumbPath, $broken ); |
1001 | | - break; |
1002 | | - } |
1003 | | - } |
1004 | | - // Doesn't exist anymore |
1005 | | - clearstatcache(); |
1006 | | - } |
1007 | | - if ( is_file( $thumbDir ) ) { |
1008 | | - // File where directory should be |
1009 | | - unlink( $thumbDir ); |
1010 | | - // Doesn't exist anymore |
1011 | | - clearstatcache(); |
1012 | | - } |
1013 | | - } |
1014 | | - |
1015 | | - /** |
1016 | | - * Get a MediaHandler instance for this image |
1017 | | - */ |
1018 | | - function getHandler() { |
1019 | | - return MediaHandler::getHandler( $this->getMimeType() ); |
1020 | | - } |
1021 | | - |
1022 | | - /** |
1023 | | - * Get a ThumbnailImage representing a file type icon |
1024 | | - * @return ThumbnailImage |
1025 | | - */ |
1026 | | - function iconThumb() { |
1027 | | - global $wgStylePath, $wgStyleDirectory; |
1028 | | - |
1029 | | - $icons = array( 'fileicon-' . $this->extension . '.png', 'fileicon.png' ); |
1030 | | - foreach( $icons as $icon ) { |
1031 | | - $path = '/common/images/icons/' . $icon; |
1032 | | - $filepath = $wgStyleDirectory . $path; |
1033 | | - if( file_exists( $filepath ) ) { |
1034 | | - return new ThumbnailImage( $wgStylePath . $path, 120, 120 ); |
1035 | | - } |
1036 | | - } |
1037 | | - return null; |
1038 | | - } |
1039 | | - |
1040 | | - /** |
1041 | | - * Get last thumbnailing error. |
1042 | | - * Largely obsolete. |
1043 | | - * @return mixed |
1044 | | - */ |
1045 | | - function getLastError() { |
1046 | | - return $this->lastError; |
1047 | | - } |
1048 | | - |
1049 | | - /** |
1050 | | - * Get all thumbnail names previously generated for this image |
1051 | | - * @param boolean $shared |
1052 | | - * @return array[]string |
1053 | | - */ |
1054 | | - function getThumbnails( $shared = false ) { |
1055 | | - if ( Image::isHashed( $shared ) ) { |
1056 | | - $this->load(); |
1057 | | - $files = array(); |
1058 | | - $dir = wfImageThumbDir( $this->name, $shared ); |
1059 | | - |
1060 | | - if ( is_dir( $dir ) ) { |
1061 | | - $handle = opendir( $dir ); |
1062 | | - |
1063 | | - if ( $handle ) { |
1064 | | - while ( false !== ( $file = readdir($handle) ) ) { |
1065 | | - if ( $file[0] != '.' ) { |
1066 | | - $files[] = $file; |
1067 | | - } |
1068 | | - } |
1069 | | - closedir( $handle ); |
1070 | | - } |
1071 | | - } |
1072 | | - } else { |
1073 | | - $files = array(); |
1074 | | - } |
1075 | | - |
1076 | | - return $files; |
1077 | | - } |
1078 | | - |
1079 | | - /** |
1080 | | - * Refresh metadata in memcached, but don't touch thumbnails or squid |
1081 | | - * @return void |
1082 | | - */ |
1083 | | - function purgeMetadataCache() { |
1084 | | - clearstatcache(); |
1085 | | - $this->loadFromFile(); |
1086 | | - $this->saveToCache(); |
1087 | | - } |
1088 | | - |
1089 | | - /** |
1090 | | - * Delete all previously generated thumbnails, refresh metadata in memcached and purge the squid |
1091 | | - * @param array $archiveFiles |
1092 | | - * @param boolean $shared |
1093 | | - * @return void |
1094 | | - */ |
1095 | | - function purgeCache( $archiveFiles = array(), $shared = false ) { |
1096 | | - global $wgUseSquid; |
1097 | | - |
1098 | | - // Refresh metadata cache |
1099 | | - $this->purgeMetadataCache(); |
1100 | | - |
1101 | | - // Delete thumbnails |
1102 | | - $files = $this->getThumbnails( $shared ); |
1103 | | - $dir = wfImageThumbDir( $this->name, $shared ); |
1104 | | - $urls = array(); |
1105 | | - foreach ( $files as $file ) { |
1106 | | - # Check that the base image name is part of the thumb name |
1107 | | - # This is a basic sanity check to avoid erasing unrelated directories |
1108 | | - if ( strpos( $file, $this->name ) !== false ) { |
1109 | | - $url = $this->thumbUrlFromName( $file ); |
1110 | | - $urls[] = $url; |
1111 | | - @unlink( "$dir/$file" ); |
1112 | | - } |
1113 | | - } |
1114 | | - |
1115 | | - // Purge the squid |
1116 | | - if ( $wgUseSquid ) { |
1117 | | - $urls[] = $this->getURL(); |
1118 | | - foreach ( $archiveFiles as $file ) { |
1119 | | - $urls[] = wfImageArchiveUrl( $file ); |
1120 | | - } |
1121 | | - wfPurgeSquidServers( $urls ); |
1122 | | - } |
1123 | | - } |
1124 | | - |
1125 | | - /** |
1126 | | - * Purge the image description page, but don't go after |
1127 | | - * pages using the image. Use when modifying file history |
1128 | | - * but not the current data. |
1129 | | - * @return void |
1130 | | - */ |
1131 | | - function purgeDescription() { |
1132 | | - $page = Title::makeTitle( NS_IMAGE, $this->name ); |
1133 | | - $page->invalidateCache(); |
1134 | | - $page->purgeSquid(); |
1135 | | - } |
1136 | | - |
1137 | | - /** |
1138 | | - * Purge metadata and all affected pages when the image is created, |
1139 | | - * deleted, or majorly updated. |
1140 | | - * @param array $urlArray A set of additional URLs may be passed to purge, |
1141 | | - * such as specific image files which have changed (param not used?) |
1142 | | - * @return void |
1143 | | - */ |
1144 | | - function purgeEverything( $urlArr=array() ) { |
1145 | | - // Delete thumbnails and refresh image metadata cache |
1146 | | - $this->purgeCache(); |
1147 | | - $this->purgeDescription(); |
1148 | | - |
1149 | | - // Purge cache of all pages using this image |
1150 | | - $update = new HTMLCacheUpdate( $this->getTitle(), 'imagelinks' ); |
1151 | | - $update->doUpdate(); |
1152 | | - } |
1153 | | - |
1154 | | - /** |
1155 | | - * Return the image history of this image, line by line. |
1156 | | - * starts with current version, then old versions. |
1157 | | - * uses $this->historyLine to check which line to return: |
1158 | | - * 0 return line for current version |
1159 | | - * 1 query for old versions, return first one |
1160 | | - * 2, ... return next old version from above query |
1161 | | - * |
1162 | | - * @public |
1163 | | - * @return mixed false on no next history, object otherwise. |
1164 | | - */ |
1165 | | - function nextHistoryLine() { |
1166 | | - $dbr = wfGetDB( DB_SLAVE ); |
1167 | | - |
1168 | | - if ( $this->historyLine == 0 ) {// called for the first time, return line from cur |
1169 | | - $this->historyRes = $dbr->select( 'image', |
1170 | | - array( |
1171 | | - 'img_size', |
1172 | | - 'img_description', |
1173 | | - 'img_user','img_user_text', |
1174 | | - 'img_timestamp', |
1175 | | - 'img_width', |
1176 | | - 'img_height', |
1177 | | - "'' AS oi_archive_name" |
1178 | | - ), |
1179 | | - array( 'img_name' => $this->title->getDBkey() ), |
1180 | | - __METHOD__ |
1181 | | - ); |
1182 | | - if ( 0 == $dbr->numRows( $this->historyRes ) ) { |
1183 | | - return FALSE; |
1184 | | - } |
1185 | | - } else if ( $this->historyLine == 1 ) { |
1186 | | - $this->historyRes = $dbr->select( 'oldimage', |
1187 | | - array( |
1188 | | - 'oi_size AS img_size', |
1189 | | - 'oi_description AS img_description', |
1190 | | - 'oi_user AS img_user', |
1191 | | - 'oi_user_text AS img_user_text', |
1192 | | - 'oi_timestamp AS img_timestamp', |
1193 | | - 'oi_width as img_width', |
1194 | | - 'oi_height as img_height', |
1195 | | - 'oi_archive_name' |
1196 | | - ), |
1197 | | - array( 'oi_name' => $this->title->getDBkey() ), |
1198 | | - __METHOD__, |
1199 | | - array( 'ORDER BY' => 'oi_timestamp DESC' ) |
1200 | | - ); |
1201 | | - } |
1202 | | - $this->historyLine ++; |
1203 | | - |
1204 | | - return $dbr->fetchObject( $this->historyRes ); |
1205 | | - } |
1206 | | - |
1207 | | - /** |
1208 | | - * Reset the history pointer to the first element of the history |
1209 | | - * @public |
1210 | | - * @return void |
1211 | | - */ |
1212 | | - function resetHistory() { |
1213 | | - $this->historyLine = 0; |
1214 | | - } |
1215 | | - |
1216 | | - /** |
1217 | | - * Return the full filesystem path to the file. Note that this does |
1218 | | - * not mean that a file actually exists under that location. |
1219 | | - * |
1220 | | - * This path depends on whether directory hashing is active or not, |
1221 | | - * i.e. whether the images are all found in the same directory, |
1222 | | - * or in hashed paths like /images/3/3c. |
1223 | | - * |
1224 | | - * @public |
1225 | | - * @param boolean $fromSharedDirectory Return the path to the file |
1226 | | - * in a shared repository (see $wgUseSharedRepository and related |
1227 | | - * options in DefaultSettings.php) instead of a local one. |
1228 | | - * @return string Full filesystem path to the file. |
1229 | | - */ |
1230 | | - function getFullPath( $fromSharedRepository = false ) { |
1231 | | - global $wgUploadDirectory, $wgSharedUploadDirectory; |
1232 | | - |
1233 | | - $dir = $fromSharedRepository ? $wgSharedUploadDirectory : |
1234 | | - $wgUploadDirectory; |
1235 | | - |
1236 | | - // $wgSharedUploadDirectory may be false, if thumb.php is used |
1237 | | - if ( $dir ) { |
1238 | | - $fullpath = $dir . wfGetHashPath($this->name, $fromSharedRepository) . $this->name; |
1239 | | - } else { |
1240 | | - $fullpath = false; |
1241 | | - } |
1242 | | - |
1243 | | - return $fullpath; |
1244 | | - } |
1245 | | - |
1246 | | - /** |
1247 | | - * @param boolean $shared |
1248 | | - * @return bool |
1249 | | - */ |
1250 | | - public static function isHashed( $shared ) { |
1251 | | - global $wgHashedUploadDirectory, $wgHashedSharedUploadDirectory; |
1252 | | - return $shared ? $wgHashedSharedUploadDirectory : $wgHashedUploadDirectory; |
1253 | | - } |
1254 | | - |
1255 | | - /** |
1256 | | - * Record an image upload in the upload log and the image table |
1257 | | - * @param string $oldver |
1258 | | - * @param string $desc |
1259 | | - * @param string $license |
1260 | | - * @param string $copyStatus |
1261 | | - * @param string $source |
1262 | | - * @param boolean $watch |
1263 | | - * @return boolean |
1264 | | - */ |
1265 | | - function recordUpload( $oldver, $desc, $license = '', $copyStatus = '', $source = '', $watch = false ) { |
1266 | | - global $wgUser, $wgUseCopyrightUpload; |
1267 | | - |
1268 | | - $dbw = wfGetDB( DB_MASTER ); |
1269 | | - |
1270 | | - // Delete thumbnails and refresh the metadata cache |
1271 | | - $this->purgeCache(); |
1272 | | - |
1273 | | - // Fail now if the image isn't there |
1274 | | - if ( !$this->fileExists || $this->fromSharedDirectory ) { |
1275 | | - wfDebug( "Image::recordUpload: File ".$this->imagePath." went missing!\n" ); |
1276 | | - return false; |
1277 | | - } |
1278 | | - |
1279 | | - if ( $wgUseCopyrightUpload ) { |
1280 | | - if ( $license != '' ) { |
1281 | | - $licensetxt = '== ' . wfMsgForContent( 'license' ) . " ==\n" . '{{' . $license . '}}' . "\n"; |
1282 | | - } |
1283 | | - $textdesc = '== ' . wfMsg ( 'filedesc' ) . " ==\n" . $desc . "\n" . |
1284 | | - '== ' . wfMsgForContent ( 'filestatus' ) . " ==\n" . $copyStatus . "\n" . |
1285 | | - "$licensetxt" . |
1286 | | - '== ' . wfMsgForContent ( 'filesource' ) . " ==\n" . $source ; |
1287 | | - } else { |
1288 | | - if ( $license != '' ) { |
1289 | | - $filedesc = $desc == '' ? '' : '== ' . wfMsg ( 'filedesc' ) . " ==\n" . $desc . "\n"; |
1290 | | - $textdesc = $filedesc . |
1291 | | - '== ' . wfMsgForContent ( 'license' ) . " ==\n" . '{{' . $license . '}}' . "\n"; |
1292 | | - } else { |
1293 | | - $textdesc = $desc; |
1294 | | - } |
1295 | | - } |
1296 | | - |
1297 | | - $now = $dbw->timestamp(); |
1298 | | - |
1299 | | - #split mime type |
1300 | | - if (strpos($this->mime,'/')!==false) { |
1301 | | - list($major,$minor)= explode('/',$this->mime,2); |
1302 | | - } |
1303 | | - else { |
1304 | | - $major= $this->mime; |
1305 | | - $minor= "unknown"; |
1306 | | - } |
1307 | | - |
1308 | | - # Test to see if the row exists using INSERT IGNORE |
1309 | | - # This avoids race conditions by locking the row until the commit, and also |
1310 | | - # doesn't deadlock. SELECT FOR UPDATE causes a deadlock for every race condition. |
1311 | | - $dbw->insert( 'image', |
1312 | | - array( |
1313 | | - 'img_name' => $this->name, |
1314 | | - 'img_size'=> $this->size, |
1315 | | - 'img_width' => intval( $this->width ), |
1316 | | - 'img_height' => intval( $this->height ), |
1317 | | - 'img_bits' => $this->bits, |
1318 | | - 'img_media_type' => $this->type, |
1319 | | - 'img_major_mime' => $major, |
1320 | | - 'img_minor_mime' => $minor, |
1321 | | - 'img_timestamp' => $now, |
1322 | | - 'img_description' => $desc, |
1323 | | - 'img_user' => $wgUser->getID(), |
1324 | | - 'img_user_text' => $wgUser->getName(), |
1325 | | - 'img_metadata' => $this->metadata, |
1326 | | - ), |
1327 | | - __METHOD__, |
1328 | | - 'IGNORE' |
1329 | | - ); |
1330 | | - |
1331 | | - if( $dbw->affectedRows() == 0 ) { |
1332 | | - # Collision, this is an update of an image |
1333 | | - # Insert previous contents into oldimage |
1334 | | - $dbw->insertSelect( 'oldimage', 'image', |
1335 | | - array( |
1336 | | - 'oi_name' => 'img_name', |
1337 | | - 'oi_archive_name' => $dbw->addQuotes( $oldver ), |
1338 | | - 'oi_size' => 'img_size', |
1339 | | - 'oi_width' => 'img_width', |
1340 | | - 'oi_height' => 'img_height', |
1341 | | - 'oi_bits' => 'img_bits', |
1342 | | - 'oi_timestamp' => 'img_timestamp', |
1343 | | - 'oi_description' => 'img_description', |
1344 | | - 'oi_user' => 'img_user', |
1345 | | - 'oi_user_text' => 'img_user_text', |
1346 | | - ), array( 'img_name' => $this->name ), __METHOD__ |
1347 | | - ); |
1348 | | - |
1349 | | - # Update the current image row |
1350 | | - $dbw->update( 'image', |
1351 | | - array( /* SET */ |
1352 | | - 'img_size' => $this->size, |
1353 | | - 'img_width' => intval( $this->width ), |
1354 | | - 'img_height' => intval( $this->height ), |
1355 | | - 'img_bits' => $this->bits, |
1356 | | - 'img_media_type' => $this->type, |
1357 | | - 'img_major_mime' => $major, |
1358 | | - 'img_minor_mime' => $minor, |
1359 | | - 'img_timestamp' => $now, |
1360 | | - 'img_description' => $desc, |
1361 | | - 'img_user' => $wgUser->getID(), |
1362 | | - 'img_user_text' => $wgUser->getName(), |
1363 | | - 'img_metadata' => $this->metadata, |
1364 | | - ), array( /* WHERE */ |
1365 | | - 'img_name' => $this->name |
1366 | | - ), __METHOD__ |
1367 | | - ); |
1368 | | - } else { |
1369 | | - # This is a new image |
1370 | | - # Update the image count |
1371 | | - $site_stats = $dbw->tableName( 'site_stats' ); |
1372 | | - $dbw->query( "UPDATE $site_stats SET ss_images=ss_images+1", __METHOD__ ); |
1373 | | - } |
1374 | | - |
1375 | | - $descTitle = $this->getTitle(); |
1376 | | - $article = new Article( $descTitle ); |
1377 | | - $minor = false; |
1378 | | - $watch = $watch || $wgUser->isWatched( $descTitle ); |
1379 | | - $suppressRC = true; // There's already a log entry, so don't double the RC load |
1380 | | - |
1381 | | - if( $descTitle->exists() ) { |
1382 | | - // TODO: insert a null revision into the page history for this update. |
1383 | | - if( $watch ) { |
1384 | | - $wgUser->addWatch( $descTitle ); |
1385 | | - } |
1386 | | - |
1387 | | - # Invalidate the cache for the description page |
1388 | | - $descTitle->invalidateCache(); |
1389 | | - $descTitle->purgeSquid(); |
1390 | | - } else { |
1391 | | - // New image; create the description page. |
1392 | | - $article->insertNewArticle( $textdesc, $desc, $minor, $watch, $suppressRC ); |
1393 | | - } |
1394 | | - |
1395 | | - # Hooks, hooks, the magic of hooks... |
1396 | | - wfRunHooks( 'FileUpload', array( $this ) ); |
1397 | | - |
1398 | | - # Add the log entry |
1399 | | - $log = new LogPage( 'upload' ); |
1400 | | - $log->addEntry( 'upload', $descTitle, $desc ); |
1401 | | - |
1402 | | - # Commit the transaction now, in case something goes wrong later |
1403 | | - # The most important thing is that images don't get lost, especially archives |
1404 | | - $dbw->immediateCommit(); |
1405 | | - |
1406 | | - # Invalidate cache for all pages using this image |
1407 | | - $update = new HTMLCacheUpdate( $this->getTitle(), 'imagelinks' ); |
1408 | | - $update->doUpdate(); |
1409 | | - |
1410 | | - return true; |
1411 | | - } |
1412 | | - |
1413 | | - /** |
1414 | | - * Get an array of Title objects which are articles which use this image |
1415 | | - * Also adds their IDs to the link cache |
1416 | | - * |
1417 | | - * This is mostly copied from Title::getLinksTo() |
1418 | | - * |
1419 | | - * @deprecated Use HTMLCacheUpdate, this function uses too much memory |
1420 | | - * @param string $options |
1421 | | - * @return array[int]Title |
1422 | | - */ |
1423 | | - function getLinksTo( $options = '' ) { |
1424 | | - wfProfileIn( __METHOD__ ); |
1425 | | - |
1426 | | - if ( $options ) { |
1427 | | - $db = wfGetDB( DB_MASTER ); |
1428 | | - } else { |
1429 | | - $db = wfGetDB( DB_SLAVE ); |
1430 | | - } |
1431 | | - $linkCache =& LinkCache::singleton(); |
1432 | | - |
1433 | | - list( $page, $imagelinks ) = $db->tableNamesN( 'page', 'imagelinks' ); |
1434 | | - $encName = $db->addQuotes( $this->name ); |
1435 | | - $sql = "SELECT page_namespace,page_title,page_id FROM $page,$imagelinks WHERE page_id=il_from AND il_to=$encName $options"; |
1436 | | - $res = $db->query( $sql, __METHOD__ ); |
1437 | | - |
1438 | | - $retVal = array(); |
1439 | | - if ( $db->numRows( $res ) ) { |
1440 | | - while ( $row = $db->fetchObject( $res ) ) { |
1441 | | - if ( $titleObj = Title::makeTitle( $row->page_namespace, $row->page_title ) ) { |
1442 | | - $linkCache->addGoodLinkObj( $row->page_id, $titleObj ); |
1443 | | - $retVal[] = $titleObj; |
1444 | | - } |
1445 | | - } |
1446 | | - } |
1447 | | - $db->freeResult( $res ); |
1448 | | - wfProfileOut( __METHOD__ ); |
1449 | | - return $retVal; |
1450 | | - } |
1451 | | - |
1452 | | - /** |
1453 | | - * @return array |
1454 | | - */ |
1455 | | - function getExifData() { |
1456 | | - $handler = $this->getHandler(); |
1457 | | - if ( !$handler || $handler->getMetadataType( $this ) != 'exif' ) { |
1458 | | - return array(); |
1459 | | - } |
1460 | | - if ( !$this->metadata ) { |
1461 | | - return array(); |
1462 | | - } |
1463 | | - $exif = unserialize( $this->metadata ); |
1464 | | - if ( !$exif ) { |
1465 | | - return array(); |
1466 | | - } |
1467 | | - unset( $exif['MEDIAWIKI_EXIF_VERSION'] ); |
1468 | | - $format = new FormatExif( $exif ); |
1469 | | - |
1470 | | - return $format->getFormattedData(); |
1471 | | - } |
1472 | | - |
1473 | | - /** |
1474 | | - * Returns true if the image does not come from the shared |
1475 | | - * image repository. |
1476 | | - * |
1477 | | - * @return bool |
1478 | | - */ |
1479 | | - function isLocal() { |
1480 | | - return !$this->fromSharedDirectory; |
1481 | | - } |
1482 | | - |
1483 | | - /** |
1484 | | - * Was this image ever deleted from the wiki? |
1485 | | - * |
1486 | | - * @return bool |
1487 | | - */ |
1488 | | - function wasDeleted() { |
1489 | | - $title = Title::makeTitle( NS_IMAGE, $this->name ); |
1490 | | - return ( $title->isDeleted() > 0 ); |
1491 | | - } |
1492 | | - |
1493 | | - /** |
1494 | | - * Delete all versions of the image. |
1495 | | - * |
1496 | | - * Moves the files into an archive directory (or deletes them) |
1497 | | - * and removes the database rows. |
1498 | | - * |
1499 | | - * Cache purging is done; logging is caller's responsibility. |
1500 | | - * |
1501 | | - * @param string $reason |
1502 | | - * @param boolean $suppress |
1503 | | - * @return boolean true on success, false on some kind of failure |
1504 | | - */ |
1505 | | - function delete( $reason, $suppress=false ) { |
1506 | | - $transaction = new FSTransaction(); |
1507 | | - $urlArr = array( $this->getURL() ); |
1508 | | - |
1509 | | - if( !FileStore::lock() ) { |
1510 | | - wfDebug( __METHOD__.": failed to acquire file store lock, aborting\n" ); |
1511 | | - return false; |
1512 | | - } |
1513 | | - |
1514 | | - try { |
1515 | | - $dbw = wfGetDB( DB_MASTER ); |
1516 | | - $dbw->begin(); |
1517 | | - |
1518 | | - // Delete old versions |
1519 | | - $result = $dbw->select( 'oldimage', |
1520 | | - array( 'oi_archive_name' ), |
1521 | | - array( 'oi_name' => $this->name ) ); |
1522 | | - |
1523 | | - while( $row = $dbw->fetchObject( $result ) ) { |
1524 | | - $oldName = $row->oi_archive_name; |
1525 | | - |
1526 | | - $transaction->add( $this->prepareDeleteOld( $oldName, $reason, $suppress ) ); |
1527 | | - |
1528 | | - // We'll need to purge this URL from caches... |
1529 | | - $urlArr[] = wfImageArchiveUrl( $oldName ); |
1530 | | - } |
1531 | | - $dbw->freeResult( $result ); |
1532 | | - |
1533 | | - // And the current version... |
1534 | | - $transaction->add( $this->prepareDeleteCurrent( $reason, $suppress ) ); |
1535 | | - |
1536 | | - $dbw->immediateCommit(); |
1537 | | - } catch( MWException $e ) { |
1538 | | - wfDebug( __METHOD__.": db error, rolling back file transactions\n" ); |
1539 | | - $transaction->rollback(); |
1540 | | - FileStore::unlock(); |
1541 | | - throw $e; |
1542 | | - } |
1543 | | - |
1544 | | - wfDebug( __METHOD__.": deleted db items, applying file transactions\n" ); |
1545 | | - $transaction->commit(); |
1546 | | - FileStore::unlock(); |
1547 | | - |
1548 | | - |
1549 | | - // Update site_stats |
1550 | | - $site_stats = $dbw->tableName( 'site_stats' ); |
1551 | | - $dbw->query( "UPDATE $site_stats SET ss_images=ss_images-1", __METHOD__ ); |
1552 | | - |
1553 | | - $this->purgeEverything( $urlArr ); |
1554 | | - |
1555 | | - return true; |
1556 | | - } |
1557 | | - |
1558 | | - |
1559 | | - /** |
1560 | | - * Delete an old version of the image. |
1561 | | - * |
1562 | | - * Moves the file into an archive directory (or deletes it) |
1563 | | - * and removes the database row. |
1564 | | - * |
1565 | | - * Cache purging is done; logging is caller's responsibility. |
1566 | | - * |
1567 | | - * @param string $archiveName |
1568 | | - * @param string $reason |
1569 | | - * @param boolean $suppress |
1570 | | - * @throws MWException or FSException on database or filestore failure |
1571 | | - * @return boolean true on success, false on some kind of failure |
1572 | | - */ |
1573 | | - function deleteOld( $archiveName, $reason, $suppress=false ) { |
1574 | | - $transaction = new FSTransaction(); |
1575 | | - $urlArr = array(); |
1576 | | - |
1577 | | - if( !FileStore::lock() ) { |
1578 | | - wfDebug( __METHOD__.": failed to acquire file store lock, aborting\n" ); |
1579 | | - return false; |
1580 | | - } |
1581 | | - |
1582 | | - $transaction = new FSTransaction(); |
1583 | | - try { |
1584 | | - $dbw = wfGetDB( DB_MASTER ); |
1585 | | - $dbw->begin(); |
1586 | | - $transaction->add( $this->prepareDeleteOld( $archiveName, $reason, $suppress ) ); |
1587 | | - $dbw->immediateCommit(); |
1588 | | - } catch( MWException $e ) { |
1589 | | - wfDebug( __METHOD__.": db error, rolling back file transaction\n" ); |
1590 | | - $transaction->rollback(); |
1591 | | - FileStore::unlock(); |
1592 | | - throw $e; |
1593 | | - } |
1594 | | - |
1595 | | - wfDebug( __METHOD__.": deleted db items, applying file transaction\n" ); |
1596 | | - $transaction->commit(); |
1597 | | - FileStore::unlock(); |
1598 | | - |
1599 | | - $this->purgeDescription(); |
1600 | | - |
1601 | | - // Squid purging |
1602 | | - global $wgUseSquid; |
1603 | | - if ( $wgUseSquid ) { |
1604 | | - $urlArr = array( |
1605 | | - wfImageArchiveUrl( $archiveName ), |
1606 | | - ); |
1607 | | - wfPurgeSquidServers( $urlArr ); |
1608 | | - } |
1609 | | - return true; |
1610 | | - } |
1611 | | - |
1612 | | - /** |
1613 | | - * Delete the current version of a file. |
1614 | | - * May throw a database error. |
1615 | | - * @param string $reason |
1616 | | - * @param boolean $suppress |
1617 | | - * @return boolean true on success, false on failure |
1618 | | - */ |
1619 | | - private function prepareDeleteCurrent( $reason, $suppress=false ) { |
1620 | | - return $this->prepareDeleteVersion( |
1621 | | - $this->getFullPath(), |
1622 | | - $reason, |
1623 | | - 'image', |
1624 | | - array( |
1625 | | - 'fa_name' => 'img_name', |
1626 | | - 'fa_archive_name' => 'NULL', |
1627 | | - 'fa_size' => 'img_size', |
1628 | | - 'fa_width' => 'img_width', |
1629 | | - 'fa_height' => 'img_height', |
1630 | | - 'fa_metadata' => 'img_metadata', |
1631 | | - 'fa_bits' => 'img_bits', |
1632 | | - 'fa_media_type' => 'img_media_type', |
1633 | | - 'fa_major_mime' => 'img_major_mime', |
1634 | | - 'fa_minor_mime' => 'img_minor_mime', |
1635 | | - 'fa_description' => 'img_description', |
1636 | | - 'fa_user' => 'img_user', |
1637 | | - 'fa_user_text' => 'img_user_text', |
1638 | | - 'fa_timestamp' => 'img_timestamp' ), |
1639 | | - array( 'img_name' => $this->name ), |
1640 | | - $suppress, |
1641 | | - __METHOD__ ); |
1642 | | - } |
1643 | | - |
1644 | | - /** |
1645 | | - * Delete a given older version of a file. |
1646 | | - * May throw a database error. |
1647 | | - * @param string $archiveName |
1648 | | - * @param string $reason |
1649 | | - * @param boolean $suppress |
1650 | | - * @return boolean true on success, false on failure |
1651 | | - */ |
1652 | | - private function prepareDeleteOld( $archiveName, $reason, $suppress=false ) { |
1653 | | - $oldpath = wfImageArchiveDir( $this->name ) . |
1654 | | - DIRECTORY_SEPARATOR . $archiveName; |
1655 | | - return $this->prepareDeleteVersion( |
1656 | | - $oldpath, |
1657 | | - $reason, |
1658 | | - 'oldimage', |
1659 | | - array( |
1660 | | - 'fa_name' => 'oi_name', |
1661 | | - 'fa_archive_name' => 'oi_archive_name', |
1662 | | - 'fa_size' => 'oi_size', |
1663 | | - 'fa_width' => 'oi_width', |
1664 | | - 'fa_height' => 'oi_height', |
1665 | | - 'fa_metadata' => 'NULL', |
1666 | | - 'fa_bits' => 'oi_bits', |
1667 | | - 'fa_media_type' => 'NULL', |
1668 | | - 'fa_major_mime' => 'NULL', |
1669 | | - 'fa_minor_mime' => 'NULL', |
1670 | | - 'fa_description' => 'oi_description', |
1671 | | - 'fa_user' => 'oi_user', |
1672 | | - 'fa_user_text' => 'oi_user_text', |
1673 | | - 'fa_timestamp' => 'oi_timestamp' ), |
1674 | | - array( |
1675 | | - 'oi_name' => $this->name, |
1676 | | - 'oi_archive_name' => $archiveName ), |
1677 | | - $suppress, |
1678 | | - __METHOD__ ); |
1679 | | - } |
1680 | | - |
1681 | | - /** |
1682 | | - * Do the dirty work of backing up an image row and its file |
1683 | | - * (if $wgSaveDeletedFiles is on) and removing the originals. |
1684 | | - * |
1685 | | - * Must be run while the file store is locked and a database |
1686 | | - * transaction is open to avoid race conditions. |
1687 | | - * |
1688 | | - * @return FSTransaction |
1689 | | - */ |
1690 | | - private function prepareDeleteVersion( $path, $reason, $table, $fieldMap, $where, $suppress=false, $fname ) { |
1691 | | - global $wgUser, $wgSaveDeletedFiles; |
1692 | | - |
1693 | | - // Dupe the file into the file store |
1694 | | - if( file_exists( $path ) ) { |
1695 | | - if( $wgSaveDeletedFiles ) { |
1696 | | - $group = 'deleted'; |
1697 | | - |
1698 | | - $store = FileStore::get( $group ); |
1699 | | - $key = FileStore::calculateKey( $path, $this->extension ); |
1700 | | - $transaction = $store->insert( $key, $path, |
1701 | | - FileStore::DELETE_ORIGINAL ); |
1702 | | - } else { |
1703 | | - $group = null; |
1704 | | - $key = null; |
1705 | | - $transaction = FileStore::deleteFile( $path ); |
1706 | | - } |
1707 | | - } else { |
1708 | | - wfDebug( __METHOD__." deleting already-missing '$path'; moving on to database\n" ); |
1709 | | - $group = null; |
1710 | | - $key = null; |
1711 | | - $transaction = new FSTransaction(); // empty |
1712 | | - } |
1713 | | - |
1714 | | - if( $transaction === false ) { |
1715 | | - // Fail to restore? |
1716 | | - wfDebug( __METHOD__.": import to file store failed, aborting\n" ); |
1717 | | - throw new MWException( "Could not archive and delete file $path" ); |
1718 | | - return false; |
1719 | | - } |
1720 | | - |
1721 | | - // Bitfields to further supress the image content |
1722 | | - // Note that currently, live images are stored elsewhere |
1723 | | - // and cannot be partially deleted |
1724 | | - $bitfield = 0; |
1725 | | - if ( $suppress ) { |
1726 | | - $bitfield |= self::DELETED_FILE; |
1727 | | - $bitfield |= self::DELETED_COMMENT; |
1728 | | - $bitfield |= self::DELETED_USER; |
1729 | | - $bitfield |= self::DELETED_RESTRICTED; |
1730 | | - } |
1731 | | - |
1732 | | - $dbw = wfGetDB( DB_MASTER ); |
1733 | | - $storageMap = array( |
1734 | | - 'fa_storage_group' => $dbw->addQuotes( $group ), |
1735 | | - 'fa_storage_key' => $dbw->addQuotes( $key ), |
1736 | | - |
1737 | | - 'fa_deleted_user' => $dbw->addQuotes( $wgUser->getId() ), |
1738 | | - 'fa_deleted_timestamp' => $dbw->timestamp(), |
1739 | | - 'fa_deleted_reason' => $dbw->addQuotes( $reason ), |
1740 | | - 'fa_deleted' => $bitfield); |
1741 | | - $allFields = array_merge( $storageMap, $fieldMap ); |
1742 | | - |
1743 | | - try { |
1744 | | - if( $wgSaveDeletedFiles ) { |
1745 | | - $dbw->insertSelect( 'filearchive', $table, $allFields, $where, $fname ); |
1746 | | - } |
1747 | | - $dbw->delete( $table, $where, $fname ); |
1748 | | - } catch( DBQueryError $e ) { |
1749 | | - // Something went horribly wrong! |
1750 | | - // Leave the file as it was... |
1751 | | - wfDebug( __METHOD__.": database error, rolling back file transaction\n" ); |
1752 | | - $transaction->rollback(); |
1753 | | - throw $e; |
1754 | | - } |
1755 | | - |
1756 | | - return $transaction; |
1757 | | - } |
1758 | | - |
1759 | | - /** |
1760 | | - * Restore all or specified deleted revisions to the given file. |
1761 | | - * Permissions and logging are left to the caller. |
1762 | | - * |
1763 | | - * May throw database exceptions on error. |
1764 | | - * |
1765 | | - * @param $versions set of record ids of deleted items to restore, |
1766 | | - * or empty to restore all revisions. |
1767 | | - * @return the number of file revisions restored if successful, |
1768 | | - * or false on failure |
1769 | | - */ |
1770 | | - function restore( $versions=array(), $Unsuppress=false ) { |
1771 | | - global $wgUser; |
1772 | | - |
1773 | | - if( !FileStore::lock() ) { |
1774 | | - wfDebug( __METHOD__." could not acquire filestore lock\n" ); |
1775 | | - return false; |
1776 | | - } |
1777 | | - |
1778 | | - $transaction = new FSTransaction(); |
1779 | | - try { |
1780 | | - $dbw = wfGetDB( DB_MASTER ); |
1781 | | - $dbw->begin(); |
1782 | | - |
1783 | | - // Re-confirm whether this image presently exists; |
1784 | | - // if no we'll need to create an image record for the |
1785 | | - // first item we restore. |
1786 | | - $exists = $dbw->selectField( 'image', '1', |
1787 | | - array( 'img_name' => $this->name ), |
1788 | | - __METHOD__ ); |
1789 | | - |
1790 | | - // Fetch all or selected archived revisions for the file, |
1791 | | - // sorted from the most recent to the oldest. |
1792 | | - $conditions = array( 'fa_name' => $this->name ); |
1793 | | - if( $versions ) { |
1794 | | - $conditions['fa_id'] = $versions; |
1795 | | - } |
1796 | | - |
1797 | | - $result = $dbw->select( 'filearchive', '*', |
1798 | | - $conditions, |
1799 | | - __METHOD__, |
1800 | | - array( 'ORDER BY' => 'fa_timestamp DESC' ) ); |
1801 | | - |
1802 | | - if( $dbw->numRows( $result ) < count( $versions ) ) { |
1803 | | - // There's some kind of conflict or confusion; |
1804 | | - // we can't restore everything we were asked to. |
1805 | | - wfDebug( __METHOD__.": couldn't find requested items\n" ); |
1806 | | - $dbw->rollback(); |
1807 | | - FileStore::unlock(); |
1808 | | - return false; |
1809 | | - } |
1810 | | - |
1811 | | - if( $dbw->numRows( $result ) == 0 ) { |
1812 | | - // Nothing to do. |
1813 | | - wfDebug( __METHOD__.": nothing to do\n" ); |
1814 | | - $dbw->rollback(); |
1815 | | - FileStore::unlock(); |
1816 | | - return true; |
1817 | | - } |
1818 | | - |
1819 | | - $revisions = 0; |
1820 | | - while( $row = $dbw->fetchObject( $result ) ) { |
1821 | | - if ( $Unsuppress ) { |
1822 | | - // Currently, fa_deleted flags fall off upon restore, lets be careful about this |
1823 | | - } else if ( ($row->fa_deleted & Revision::DELETED_RESTRICTED) && !$wgUser->isAllowed('hiderevision') ) { |
1824 | | - // Skip restoring file revisions that the user cannot restore |
1825 | | - continue; |
1826 | | - } |
1827 | | - $revisions++; |
1828 | | - $store = FileStore::get( $row->fa_storage_group ); |
1829 | | - if( !$store ) { |
1830 | | - wfDebug( __METHOD__.": skipping row with no file.\n" ); |
1831 | | - continue; |
1832 | | - } |
1833 | | - |
1834 | | - if( $revisions == 1 && !$exists ) { |
1835 | | - $destDir = wfImageDir( $row->fa_name ); |
1836 | | - if ( !is_dir( $destDir ) ) { |
1837 | | - wfMkdirParents( $destDir ); |
1838 | | - } |
1839 | | - $destPath = $destDir . DIRECTORY_SEPARATOR . $row->fa_name; |
1840 | | - |
1841 | | - // We may have to fill in data if this was originally |
1842 | | - // an archived file revision. |
1843 | | - if( is_null( $row->fa_metadata ) ) { |
1844 | | - $tempFile = $store->filePath( $row->fa_storage_key ); |
1845 | | - |
1846 | | - $magic = MimeMagic::singleton(); |
1847 | | - $mime = $magic->guessMimeType( $tempFile, true ); |
1848 | | - $media_type = $magic->getMediaType( $tempFile, $mime ); |
1849 | | - list( $major_mime, $minor_mime ) = self::splitMime( $mime ); |
1850 | | - $handler = MediaHandler::getHandler( $mime ); |
1851 | | - if ( $handler ) { |
1852 | | - $metadata = $handler->getMetadata( $image, $tempFile ); |
1853 | | - } else { |
1854 | | - $metadata = ''; |
1855 | | - } |
1856 | | - } else { |
1857 | | - $metadata = $row->fa_metadata; |
1858 | | - $major_mime = $row->fa_major_mime; |
1859 | | - $minor_mime = $row->fa_minor_mime; |
1860 | | - $media_type = $row->fa_media_type; |
1861 | | - } |
1862 | | - |
1863 | | - $table = 'image'; |
1864 | | - $fields = array( |
1865 | | - 'img_name' => $row->fa_name, |
1866 | | - 'img_size' => $row->fa_size, |
1867 | | - 'img_width' => $row->fa_width, |
1868 | | - 'img_height' => $row->fa_height, |
1869 | | - 'img_metadata' => $metadata, |
1870 | | - 'img_bits' => $row->fa_bits, |
1871 | | - 'img_media_type' => $media_type, |
1872 | | - 'img_major_mime' => $major_mime, |
1873 | | - 'img_minor_mime' => $minor_mime, |
1874 | | - 'img_description' => $row->fa_description, |
1875 | | - 'img_user' => $row->fa_user, |
1876 | | - 'img_user_text' => $row->fa_user_text, |
1877 | | - 'img_timestamp' => $row->fa_timestamp ); |
1878 | | - } else { |
1879 | | - $archiveName = $row->fa_archive_name; |
1880 | | - if( $archiveName == '' ) { |
1881 | | - // This was originally a current version; we |
1882 | | - // have to devise a new archive name for it. |
1883 | | - // Format is <timestamp of archiving>!<name> |
1884 | | - $archiveName = |
1885 | | - wfTimestamp( TS_MW, $row->fa_deleted_timestamp ) . |
1886 | | - '!' . $row->fa_name; |
1887 | | - } |
1888 | | - $destDir = wfImageArchiveDir( $row->fa_name ); |
1889 | | - if ( !is_dir( $destDir ) ) { |
1890 | | - wfMkdirParents( $destDir ); |
1891 | | - } |
1892 | | - $destPath = $destDir . DIRECTORY_SEPARATOR . $archiveName; |
1893 | | - |
1894 | | - $table = 'oldimage'; |
1895 | | - $fields = array( |
1896 | | - 'oi_name' => $row->fa_name, |
1897 | | - 'oi_archive_name' => $archiveName, |
1898 | | - 'oi_size' => $row->fa_size, |
1899 | | - 'oi_width' => $row->fa_width, |
1900 | | - 'oi_height' => $row->fa_height, |
1901 | | - 'oi_bits' => $row->fa_bits, |
1902 | | - 'oi_description' => $row->fa_description, |
1903 | | - 'oi_user' => $row->fa_user, |
1904 | | - 'oi_user_text' => $row->fa_user_text, |
1905 | | - 'oi_timestamp' => $row->fa_timestamp ); |
1906 | | - } |
1907 | | - |
1908 | | - $dbw->insert( $table, $fields, __METHOD__ ); |
1909 | | - // @todo this delete is not totally safe, potentially |
1910 | | - $dbw->delete( 'filearchive', |
1911 | | - array( 'fa_id' => $row->fa_id ), |
1912 | | - __METHOD__ ); |
1913 | | - |
1914 | | - // Check if any other stored revisions use this file; |
1915 | | - // if so, we shouldn't remove the file from the deletion |
1916 | | - // archives so they will still work. |
1917 | | - $useCount = $dbw->selectField( 'filearchive', |
1918 | | - 'COUNT(*)', |
1919 | | - array( |
1920 | | - 'fa_storage_group' => $row->fa_storage_group, |
1921 | | - 'fa_storage_key' => $row->fa_storage_key ), |
1922 | | - __METHOD__ ); |
1923 | | - if( $useCount == 0 ) { |
1924 | | - wfDebug( __METHOD__.": nothing else using {$row->fa_storage_key}, will deleting after\n" ); |
1925 | | - $flags = FileStore::DELETE_ORIGINAL; |
1926 | | - } else { |
1927 | | - $flags = 0; |
1928 | | - } |
1929 | | - |
1930 | | - $transaction->add( $store->export( $row->fa_storage_key, |
1931 | | - $destPath, $flags ) ); |
1932 | | - } |
1933 | | - |
1934 | | - $dbw->immediateCommit(); |
1935 | | - } catch( MWException $e ) { |
1936 | | - wfDebug( __METHOD__." caught error, aborting\n" ); |
1937 | | - $transaction->rollback(); |
1938 | | - throw $e; |
1939 | | - } |
1940 | | - |
1941 | | - $transaction->commit(); |
1942 | | - FileStore::unlock(); |
1943 | | - |
1944 | | - if( $revisions > 0 ) { |
1945 | | - if( !$exists ) { |
1946 | | - wfDebug( __METHOD__." restored $revisions items, creating a new current\n" ); |
1947 | | - |
1948 | | - // Update site_stats |
1949 | | - $site_stats = $dbw->tableName( 'site_stats' ); |
1950 | | - $dbw->query( "UPDATE $site_stats SET ss_images=ss_images+1", __METHOD__ ); |
1951 | | - |
1952 | | - $this->purgeEverything(); |
1953 | | - } else { |
1954 | | - wfDebug( __METHOD__." restored $revisions as archived versions\n" ); |
1955 | | - $this->purgeDescription(); |
1956 | | - } |
1957 | | - } |
1958 | | - |
1959 | | - return $revisions; |
1960 | | - } |
1961 | | - |
1962 | | - /** |
1963 | | - * Returns 'true' if this image is a multipage document, e.g. a DJVU |
1964 | | - * document. |
1965 | | - * |
1966 | | - * @return Bool |
1967 | | - */ |
1968 | | - function isMultipage() { |
1969 | | - $handler = $this->getHandler(); |
1970 | | - return $handler && $handler->isMultiPage(); |
1971 | | - } |
1972 | | - |
1973 | | - /** |
1974 | | - * Returns the number of pages of a multipage document, or NULL for |
1975 | | - * documents which aren't multipage documents |
1976 | | - */ |
1977 | | - function pageCount() { |
1978 | | - $handler = $this->getHandler(); |
1979 | | - if ( $handler && $handler->isMultiPage() ) { |
1980 | | - return $handler->pageCount( $this ); |
1981 | | - } else { |
1982 | | - return null; |
1983 | | - } |
1984 | | - } |
1985 | | - |
1986 | | - static function getCommonsDB() { |
1987 | | - static $dbc; |
1988 | | - global $wgLoadBalancer, $wgSharedUploadDBname; |
1989 | | - if ( !isset( $dbc ) ) { |
1990 | | - $i = $wgLoadBalancer->getGroupIndex( 'commons' ); |
1991 | | - $dbinfo = $wgLoadBalancer->mServers[$i]; |
1992 | | - $dbc = new Database( $dbinfo['host'], $dbinfo['user'], |
1993 | | - $dbinfo['password'], $wgSharedUploadDBname ); |
1994 | | - } |
1995 | | - return $dbc; |
1996 | | - } |
1997 | | - |
1998 | | - /** |
1999 | | - * Calculate the height of a thumbnail using the source and destination width |
2000 | | - */ |
2001 | | - static function scaleHeight( $srcWidth, $srcHeight, $dstWidth ) { |
2002 | | - // Exact integer multiply followed by division |
2003 | | - if ( $srcWidth == 0 ) { |
2004 | | - return 0; |
2005 | | - } else { |
2006 | | - return round( $srcHeight * $dstWidth / $srcWidth ); |
2007 | | - } |
2008 | | - } |
2009 | | - |
2010 | | - /** |
2011 | | - * Get an image size array like that returned by getimagesize(), or false if it |
2012 | | - * can't be determined. |
2013 | | - * |
2014 | | - * @param string $fileName The filename |
2015 | | - * @return array |
2016 | | - */ |
2017 | | - function getImageSize( $fileName ) { |
2018 | | - $handler = $this->getHandler(); |
2019 | | - return $handler->getImageSize( $this, $fileName ); |
2020 | | - } |
2021 | | - |
2022 | | - /** |
2023 | | - * Get the thumbnail extension and MIME type for a given source MIME type |
2024 | | - * @return array thumbnail extension and MIME type |
2025 | | - */ |
2026 | | - static function getThumbType( $ext, $mime ) { |
2027 | | - $handler = MediaHandler::getHandler( $mime ); |
2028 | | - if ( $handler ) { |
2029 | | - return $handler->getThumbType( $ext, $mime ); |
2030 | | - } else { |
2031 | | - return array( $ext, $mime ); |
2032 | | - } |
2033 | | - } |
2034 | | - |
2035 | | -} //class |
2036 | | - |
2037 | | - |
2038 | | -/** |
2039 | | - * @addtogroup Media |
2040 | | - */ |
2041 | | -class ArchivedFile |
2042 | | -{ |
2043 | | - /** |
2044 | | - * Returns a file object from the filearchive table |
2045 | | - * In the future, all current and old image storage |
2046 | | - * may use FileStore. There will be a "old" storage |
2047 | | - * for current and previous file revisions as well as |
2048 | | - * the "deleted" group for archived revisions |
2049 | | - * @param $title, the corresponding image page title |
2050 | | - * @param $id, the image id, a unique key |
2051 | | - * @param $key, optional storage key |
2052 | | - * @return ResultWrapper |
2053 | | - */ |
2054 | | - function ArchivedFile( $title, $id=0, $key='' ) { |
2055 | | - if( !is_object( $title ) ) { |
2056 | | - throw new MWException( 'Image constructor given bogus title.' ); |
2057 | | - } |
2058 | | - $conds = ($id) ? "fa_id = $id" : "fa_storage_key = '$key'"; |
2059 | | - if( $title->getNamespace() == NS_IMAGE ) { |
2060 | | - $dbr = wfGetDB( DB_SLAVE ); |
2061 | | - $res = $dbr->select( 'filearchive', |
2062 | | - array( |
2063 | | - 'fa_id', |
2064 | | - 'fa_name', |
2065 | | - 'fa_storage_key', |
2066 | | - 'fa_storage_group', |
2067 | | - 'fa_size', |
2068 | | - 'fa_bits', |
2069 | | - 'fa_width', |
2070 | | - 'fa_height', |
2071 | | - 'fa_metadata', |
2072 | | - 'fa_media_type', |
2073 | | - 'fa_major_mime', |
2074 | | - 'fa_minor_mime', |
2075 | | - 'fa_description', |
2076 | | - 'fa_user', |
2077 | | - 'fa_user_text', |
2078 | | - 'fa_timestamp', |
2079 | | - 'fa_deleted' ), |
2080 | | - array( |
2081 | | - 'fa_name' => $title->getDbKey(), |
2082 | | - $conds ), |
2083 | | - __METHOD__, |
2084 | | - array( 'ORDER BY' => 'fa_timestamp DESC' ) ); |
2085 | | - |
2086 | | - if ( $dbr->numRows( $res ) == 0 ) { |
2087 | | - // this revision does not exist? |
2088 | | - return; |
2089 | | - } |
2090 | | - $ret = $dbr->resultObject( $res ); |
2091 | | - $row = $ret->fetchObject(); |
2092 | | - |
2093 | | - // initialize fields for filestore image object |
2094 | | - $this->mId = intval($row->fa_id); |
2095 | | - $this->mName = $row->fa_name; |
2096 | | - $this->mGroup = $row->fa_storage_group; |
2097 | | - $this->mKey = $row->fa_storage_key; |
2098 | | - $this->mSize = $row->fa_size; |
2099 | | - $this->mBits = $row->fa_bits; |
2100 | | - $this->mWidth = $row->fa_width; |
2101 | | - $this->mHeight = $row->fa_height; |
2102 | | - $this->mMetaData = $row->fa_metadata; |
2103 | | - $this->mMime = "$row->fa_major_mime/$row->fa_minor_mime"; |
2104 | | - $this->mType = $row->fa_media_type; |
2105 | | - $this->mDescription = $row->fa_description; |
2106 | | - $this->mUser = $row->fa_user; |
2107 | | - $this->mUserText = $row->fa_user_text; |
2108 | | - $this->mTimestamp = $row->fa_timestamp; |
2109 | | - $this->mDeleted = $row->fa_deleted; |
2110 | | - } else { |
2111 | | - throw new MWException( 'This title does not correspond to an image page.' ); |
2112 | | - return; |
2113 | | - } |
2114 | | - return true; |
2115 | | - } |
2116 | | - |
2117 | | - /** |
2118 | | - * int $field one of DELETED_* bitfield constants |
2119 | | - * for file or revision rows |
2120 | | - * @return bool |
2121 | | - */ |
2122 | | - function isDeleted( $field ) { |
2123 | | - return ($this->mDeleted & $field) == $field; |
2124 | | - } |
2125 | | - |
2126 | | - /** |
2127 | | - * Determine if the current user is allowed to view a particular |
2128 | | - * field of this FileStore image file, if it's marked as deleted. |
2129 | | - * @param int $field |
2130 | | - * @return bool |
2131 | | - */ |
2132 | | - function userCan( $field ) { |
2133 | | - if( isset($this->mDeleted) && ($this->mDeleted & $field) == $field ) { |
2134 | | - // images |
2135 | | - global $wgUser; |
2136 | | - $permission = ( $this->mDeleted & Revision::DELETED_RESTRICTED ) == Revision::DELETED_RESTRICTED |
2137 | | - ? 'hiderevision' |
2138 | | - : 'deleterevision'; |
2139 | | - wfDebug( "Checking for $permission due to $field match on $this->mDeleted\n" ); |
2140 | | - return $wgUser->isAllowed( $permission ); |
2141 | | - } else { |
2142 | | - return true; |
2143 | | - } |
2144 | | - } |
2145 | | -} |
2146 | | - |
2147 | | -/** |
2148 | | - * Aliases for backwards compatibility with 1.6 |
2149 | | - */ |
2150 | | -define( 'MW_IMG_DELETED_FILE', Image::DELETED_FILE ); |
2151 | | -define( 'MW_IMG_DELETED_COMMENT', Image::DELETED_COMMENT ); |
2152 | | -define( 'MW_IMG_DELETED_USER', Image::DELETED_USER ); |
2153 | | -define( 'MW_IMG_DELETED_RESTRICTED', Image::DELETED_RESTRICTED ); |
2154 | | - |
2155 | | -?> |
Index: branches/liquidthreads/includes/SpecialWhatlinkshere.php |
— | — | @@ -231,8 +231,10 @@ |
232 | 232 | } |
233 | 233 | |
234 | 234 | //add whatlinkshere link |
235 | | - $whatlink=$this->skin->makeKnownLinkObj( SpecialPage::getTitleFor( 'Whatlinkshere', $nt->getPrefixedDBkey() ), wfMsgHtml( 'whatlinkshere-links' ) ); |
236 | | - $wgOut->addHTML(' ' . $whatlink); |
| 235 | + $whatlink = $this->skin->makeKnownLinkObj( |
| 236 | + SpecialPage::getTitleFor( 'Whatlinkshere', $nt->getPrefixedDBkey() ), |
| 237 | + wfMsgHtml( 'whatlinkshere-links' ) ); |
| 238 | + $wgOut->addHTML(" ($whatlink)" ); |
237 | 239 | |
238 | 240 | if ( $row->page_is_redirect ) { |
239 | 241 | if ( $level < 2 ) { |
Index: branches/liquidthreads/includes/ExternalEdit.php |
— | — | @@ -46,7 +46,7 @@ |
47 | 47 | $extension="wiki"; |
48 | 48 | } elseif($this->mMode=="file") { |
49 | 49 | $type="Edit file"; |
50 | | - $image = new Image( $this->mTitle ); |
| 50 | + $image = wfLocalFile( $this->mTitle ); |
51 | 51 | $img_url = $image->getURL(); |
52 | 52 | if(strpos($img_url,"://")) { |
53 | 53 | $url = $img_url; |
Index: branches/liquidthreads/includes/SearchEngine.php |
— | — | @@ -122,8 +122,8 @@ |
123 | 123 | # There may have been a funny upload, or it may be on a shared |
124 | 124 | # file repository such as Wikimedia Commons. |
125 | 125 | if( $title->getNamespace() == NS_IMAGE ) { |
126 | | - $image = new Image( $title ); |
127 | | - if( $image->exists() ) { |
| 126 | + $image = wfFindFile( $title ); |
| 127 | + if( $image ) { |
128 | 128 | return $title; |
129 | 129 | } |
130 | 130 | } |
Index: branches/liquidthreads/includes/AutoLoader.php |
— | — | @@ -96,8 +96,6 @@ |
97 | 97 | 'HTMLCacheUpdateJob' => 'includes/HTMLCacheUpdate.php', |
98 | 98 | 'EnotifNotifyJob' => 'includes/JobQueue.php', |
99 | 99 | 'Http' => 'includes/HttpFunctions.php', |
100 | | - 'Image' => 'includes/Image.php', |
101 | | - 'ArchivedFile' => 'includes/Image.php', |
102 | 100 | 'IP' => 'includes/IP.php', |
103 | 101 | 'ThumbnailImage' => 'includes/Image.php', |
104 | 102 | 'ImageGallery' => 'includes/ImageGallery.php', |
— | — | @@ -250,6 +248,19 @@ |
251 | 249 | 'memcached' => 'includes/memcached-client.php', |
252 | 250 | 'EmaillingJob' => 'includes/JobQueue.php', |
253 | 251 | |
| 252 | + # filerepo |
| 253 | + 'ArchivedFile' => 'includes/filerepo/ArchivedFile.php', |
| 254 | + 'File' => 'includes/filerepo/File.php', |
| 255 | + 'ForeignDBFile' => 'includes/filerepo/ForeignDBFile.php', |
| 256 | + 'ForeignDBRepo' => 'includes/filerepo/ForeignDBRepo.php', |
| 257 | + 'FSRepo' => 'includes/filerepo/FSRepo.php', |
| 258 | + 'Image' => 'includes/filerepo/LocalFile.php', |
| 259 | + 'LocalFile' => 'includes/filerepo/LocalFile.php', |
| 260 | + 'LocalRepo' => 'includes/filerepo/LocalRepo.php', |
| 261 | + 'OldLocalFile' => 'includes/filerepo/OldLocalFile.php', |
| 262 | + 'RepoGroup' => 'includes/filerepo/RepoGroup.php', |
| 263 | + 'UnregisteredLocalFile' => 'includes/filerepo/UnregisteredLocalFile.php', |
| 264 | + |
254 | 265 | # Media |
255 | 266 | 'BitmapHandler' => 'includes/media/Bitmap.php', |
256 | 267 | 'BmpHandler' => 'includes/media/BMP.php', |
Index: branches/liquidthreads/includes/ImageQueryPage.php |
— | — | @@ -30,8 +30,8 @@ |
31 | 31 | # $num [should update this to use a Pager] |
32 | 32 | for( $i = 0; $i < $num && $row = $dbr->fetchObject( $res ); $i++ ) { |
33 | 33 | $image = $this->prepareImage( $row ); |
34 | | - if( $image instanceof Image ) { |
35 | | - $gallery->add( $image, $this->getCellHtml( $row ) ); |
| 34 | + if( $image ) { |
| 35 | + $gallery->add( $image->getTitle(), $this->getCellHtml( $row ) ); |
36 | 36 | } |
37 | 37 | } |
38 | 38 | |
— | — | @@ -49,7 +49,7 @@ |
50 | 50 | $namespace = isset( $row->namespace ) ? $row->namespace : NS_IMAGE; |
51 | 51 | $title = Title::makeTitleSafe( $namespace, $row->title ); |
52 | 52 | return ( $title instanceof Title && $title->getNamespace() == NS_IMAGE ) |
53 | | - ? new Image( $title ) |
| 53 | + ? wfFindFile( $title ) |
54 | 54 | : null; |
55 | 55 | } |
56 | 56 | |
Index: branches/liquidthreads/includes/filerepo/FSRepo.php |
— | — | @@ -0,0 +1,412 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * A repository for files accessible via the local filesystem. Does not support |
| 6 | + * database access or registration. |
| 7 | + * |
| 8 | + * TODO: split off abstract base FileRepo |
| 9 | + */ |
| 10 | + |
| 11 | +class FSRepo { |
| 12 | + const DELETE_SOURCE = 1; |
| 13 | + |
| 14 | + var $directory, $url, $hashLevels, $thumbScriptUrl, $transformVia404; |
| 15 | + var $descBaseUrl, $scriptDirUrl, $articleUrl, $fetchDescription; |
| 16 | + var $fileFactory = array( 'UnregisteredLocalFile', 'newFromTitle' ); |
| 17 | + var $oldFileFactory = false; |
| 18 | + |
| 19 | + function __construct( $info ) { |
| 20 | + // Required settings |
| 21 | + $this->name = $info['name']; |
| 22 | + $this->directory = $info['directory']; |
| 23 | + $this->url = $info['url']; |
| 24 | + $this->hashLevels = $info['hashLevels']; |
| 25 | + $this->transformVia404 = !empty( $info['transformVia404'] ); |
| 26 | + |
| 27 | + // Optional settings |
| 28 | + foreach ( array( 'descBaseUrl', 'scriptDirUrl', 'articleUrl', 'fetchDescription', |
| 29 | + 'thumbScriptUrl' ) as $var ) |
| 30 | + { |
| 31 | + if ( isset( $info[$var] ) ) { |
| 32 | + $this->$var = $info[$var]; |
| 33 | + } |
| 34 | + } |
| 35 | + } |
| 36 | + |
| 37 | + /** |
| 38 | + * Create a new File object from the local repository |
| 39 | + * @param mixed $title Title object or string |
| 40 | + * @param mixed $time Time at which the image is supposed to have existed. |
| 41 | + * If this is specified, the returned object will be an |
| 42 | + * instance of the repository's old file class instead of |
| 43 | + * a current file. Repositories not supporting version |
| 44 | + * control should return false if this parameter is set. |
| 45 | + */ |
| 46 | + function newFile( $title, $time = false ) { |
| 47 | + if ( !($title instanceof Title) ) { |
| 48 | + $title = Title::makeTitleSafe( NS_IMAGE, $title ); |
| 49 | + if ( !is_object( $title ) ) { |
| 50 | + return null; |
| 51 | + } |
| 52 | + } |
| 53 | + if ( $time ) { |
| 54 | + if ( $this->oldFileFactory ) { |
| 55 | + return call_user_func( $this->oldFileFactory, $title, $this, $time ); |
| 56 | + } else { |
| 57 | + return false; |
| 58 | + } |
| 59 | + } else { |
| 60 | + return call_user_func( $this->fileFactory, $title, $this ); |
| 61 | + } |
| 62 | + } |
| 63 | + |
| 64 | + /** |
| 65 | + * Find an instance of the named file that existed at the specified time |
| 66 | + * Returns false if the file did not exist. Repositories not supporting |
| 67 | + * version control should return false if the time is specified. |
| 68 | + * |
| 69 | + * @param mixed $time 14-character timestamp, or false for the current version |
| 70 | + */ |
| 71 | + function findFile( $title, $time = false ) { |
| 72 | + # First try the current version of the file to see if it precedes the timestamp |
| 73 | + $img = $this->newFile( $title ); |
| 74 | + if ( !$img ) { |
| 75 | + return false; |
| 76 | + } |
| 77 | + if ( $img->exists() && ( !$time || $img->getTimestamp() <= $time ) ) { |
| 78 | + return $img; |
| 79 | + } |
| 80 | + # Now try an old version of the file |
| 81 | + $img = $this->newFile( $title, $time ); |
| 82 | + if ( $img->exists() ) { |
| 83 | + return $img; |
| 84 | + } |
| 85 | + } |
| 86 | + |
| 87 | + /** |
| 88 | + * Get the public root directory of the repository. |
| 89 | + */ |
| 90 | + function getRootDirectory() { |
| 91 | + return $this->directory; |
| 92 | + } |
| 93 | + |
| 94 | + /** |
| 95 | + * Get the public root URL of the repository |
| 96 | + */ |
| 97 | + function getRootUrl() { |
| 98 | + return $this->url; |
| 99 | + } |
| 100 | + |
| 101 | + /** |
| 102 | + * Returns true if the repository uses a multi-level directory structure |
| 103 | + */ |
| 104 | + function isHashed() { |
| 105 | + return (bool)$this->hashLevels; |
| 106 | + } |
| 107 | + |
| 108 | + /** |
| 109 | + * Get the URL of thumb.php |
| 110 | + */ |
| 111 | + function getThumbScriptUrl() { |
| 112 | + return $this->thumbScriptUrl; |
| 113 | + } |
| 114 | + |
| 115 | + /** |
| 116 | + * Returns true if the repository can transform files via a 404 handler |
| 117 | + */ |
| 118 | + function canTransformVia404() { |
| 119 | + return $this->transformVia404; |
| 120 | + } |
| 121 | + |
| 122 | + /** |
| 123 | + * Get the local directory corresponding to one of the three basic zones |
| 124 | + */ |
| 125 | + function getZonePath( $zone ) { |
| 126 | + switch ( $zone ) { |
| 127 | + case 'public': |
| 128 | + return $this->directory; |
| 129 | + case 'temp': |
| 130 | + return "{$this->directory}/temp"; |
| 131 | + case 'deleted': |
| 132 | + return $GLOBALS['wgFileStore']['deleted']['directory']; |
| 133 | + default: |
| 134 | + return false; |
| 135 | + } |
| 136 | + } |
| 137 | + |
| 138 | + /** |
| 139 | + * Get the URL corresponding to one of the three basic zones |
| 140 | + */ |
| 141 | + function getZoneUrl( $zone ) { |
| 142 | + switch ( $zone ) { |
| 143 | + case 'public': |
| 144 | + return $this->url; |
| 145 | + case 'temp': |
| 146 | + return "{$this->url}/temp"; |
| 147 | + case 'deleted': |
| 148 | + return $GLOBALS['wgFileStore']['deleted']['url']; |
| 149 | + default: |
| 150 | + return false; |
| 151 | + } |
| 152 | + } |
| 153 | + |
| 154 | + /** |
| 155 | + * Get a URL referring to this repository, with the private mwrepo protocol. |
| 156 | + */ |
| 157 | + function getVirtualUrl( $suffix = false ) { |
| 158 | + $path = 'mwrepo://'; |
| 159 | + if ( $suffix !== false ) { |
| 160 | + $path .= '/' . $suffix; |
| 161 | + } |
| 162 | + return $path; |
| 163 | + } |
| 164 | + |
| 165 | + /** |
| 166 | + * Get the local path corresponding to a virtual URL |
| 167 | + */ |
| 168 | + function resolveVirtualUrl( $url ) { |
| 169 | + if ( substr( $url, 0, 9 ) != 'mwrepo://' ) { |
| 170 | + throw new MWException( __METHOD__.': unknown protoocl' ); |
| 171 | + } |
| 172 | + |
| 173 | + $bits = explode( '/', substr( $url, 9 ), 3 ); |
| 174 | + if ( count( $bits ) != 3 ) { |
| 175 | + throw new MWException( __METHOD__.": invalid mwrepo URL: $url" ); |
| 176 | + } |
| 177 | + list( $host, $zone, $rel ) = $bits; |
| 178 | + if ( $host !== '' ) { |
| 179 | + throw new MWException( __METHOD__.": fetching from a foreign repo is not supported" ); |
| 180 | + } |
| 181 | + $base = $this->getZonePath( $zone ); |
| 182 | + if ( !$base ) { |
| 183 | + throw new MWException( __METHOD__.": invalid zone: $zone" ); |
| 184 | + } |
| 185 | + return $base . '/' . urldecode( $rel ); |
| 186 | + } |
| 187 | + |
| 188 | + /** |
| 189 | + * Store a file to a given destination. |
| 190 | + */ |
| 191 | + function store( $srcPath, $dstZone, $dstRel, $flags = 0 ) { |
| 192 | + $root = $this->getZonePath( $dstZone ); |
| 193 | + if ( !$root ) { |
| 194 | + throw new MWException( "Invalid zone: $dstZone" ); |
| 195 | + } |
| 196 | + $dstPath = "$root/$dstRel"; |
| 197 | + |
| 198 | + if ( !is_dir( dirname( $dstPath ) ) ) { |
| 199 | + wfMkdirParents( dirname( $dstPath ) ); |
| 200 | + } |
| 201 | + |
| 202 | + if ( substr( $srcPath, 0, 9 ) == 'mwrepo://' ) { |
| 203 | + $srcPath = $this->resolveVirtualUrl( $srcPath ); |
| 204 | + } |
| 205 | + |
| 206 | + if ( $flags & self::DELETE_SOURCE ) { |
| 207 | + if ( !rename( $srcPath, $dstPath ) ) { |
| 208 | + return new WikiErrorMsg( 'filerenameerror', wfEscapeWikiText( $srcPath ), |
| 209 | + wfEscapeWikiText( $dstPath ) ); |
| 210 | + } |
| 211 | + } else { |
| 212 | + if ( !copy( $srcPath, $dstPath ) ) { |
| 213 | + return new WikiErrorMsg( 'filecopyerror', wfEscapeWikiText( $srcPath ), |
| 214 | + wfEscapeWikiText( $dstPath ) ); |
| 215 | + } |
| 216 | + } |
| 217 | + chmod( $dstPath, 0644 ); |
| 218 | + return true; |
| 219 | + } |
| 220 | + |
| 221 | + /** |
| 222 | + * Pick a random name in the temp zone and store a file to it. |
| 223 | + * Returns the URL, or a WikiError on failure. |
| 224 | + * @param string $originalName The base name of the file as specified |
| 225 | + * by the user. The file extension will be maintained. |
| 226 | + * @param string $srcPath The current location of the file. |
| 227 | + */ |
| 228 | + function storeTemp( $originalName, $srcPath ) { |
| 229 | + $dstRel = $this->getHashPath( $originalName ) . |
| 230 | + gmdate( "YmdHis" ) . '!' . $originalName; |
| 231 | + $result = $this->store( $srcPath, 'temp', $dstRel ); |
| 232 | + if ( WikiError::isError( $result ) ) { |
| 233 | + return $result; |
| 234 | + } else { |
| 235 | + return $this->getVirtualUrl( "temp/$dstRel" ); |
| 236 | + } |
| 237 | + } |
| 238 | + |
| 239 | + /** |
| 240 | + * Copy or move a file either from the local filesystem or from an mwrepo:// |
| 241 | + * virtual URL, into this repository at the specified destination location. |
| 242 | + * |
| 243 | + * @param string $srcPath The source path or URL |
| 244 | + * @param string $dstPath The destination relative path |
| 245 | + * @param string $archivePath The relative path where the existing file is to |
| 246 | + * be archived, if there is one. |
| 247 | + * @param integer $flags Bitfield, may be FSRepo::DELETE_SOURCE to indicate |
| 248 | + * that the source file should be deleted if possible |
| 249 | + */ |
| 250 | + function publish( $srcPath, $dstPath, $archivePath, $flags = 0 ) { |
| 251 | + if ( substr( $srcPath, 0, 9 ) == 'mwrepo://' ) { |
| 252 | + $srcPath = $this->resolveVirtualUrl( $srcPath ); |
| 253 | + } |
| 254 | + $dstDir = dirname( $dstPath ); |
| 255 | + if ( !is_dir( $dstDir ) ) wfMkdirParents( $dstDir ); |
| 256 | + |
| 257 | + if( is_file( $dstPath ) ) { |
| 258 | + $archiveDir = dirname( $archivePath ); |
| 259 | + if ( !is_dir( $archiveDir ) ) wfMkdirParents( $archiveDir ); |
| 260 | + wfSuppressWarnings(); |
| 261 | + $success = rename( $dstPath, $archivePath ); |
| 262 | + wfRestoreWarnings(); |
| 263 | + |
| 264 | + if( ! $success ) { |
| 265 | + return new WikiErrorMsg( 'filerenameerror', wfEscapeWikiText( $dstPath ), |
| 266 | + wfEscapeWikiText( $archivePath ) ); |
| 267 | + } |
| 268 | + else wfDebug(__METHOD__.": moved file $dstPath to $archivePath\n"); |
| 269 | + $status = 'archived'; |
| 270 | + } |
| 271 | + else { |
| 272 | + $status = 'new'; |
| 273 | + } |
| 274 | + |
| 275 | + $error = false; |
| 276 | + wfSuppressWarnings(); |
| 277 | + if ( $flags & self::DELETE_SOURCE ) { |
| 278 | + if ( !rename( $srcPath, $dstPath ) ) { |
| 279 | + $error = new WikiErrorMsg( 'filerenameerror', wfEscapeWikiText( $srcPath ), |
| 280 | + wfEscapeWikiText( $dstPath ) ); |
| 281 | + } |
| 282 | + } else { |
| 283 | + if ( !copy( $srcPath, $dstPath ) ) { |
| 284 | + $error = new WikiErrorMsg( 'filerenameerror', wfEscapeWikiText( $srcPath ), |
| 285 | + wfEscapeWikiText( $dstPath ) ); |
| 286 | + } |
| 287 | + } |
| 288 | + wfRestoreWarnings(); |
| 289 | + |
| 290 | + if( $error ) { |
| 291 | + return $error; |
| 292 | + } else { |
| 293 | + wfDebug(__METHOD__.": wrote tempfile $srcPath to $dstPath\n"); |
| 294 | + } |
| 295 | + |
| 296 | + chmod( $dstPath, 0644 ); |
| 297 | + return $status; |
| 298 | + } |
| 299 | + |
| 300 | + /** |
| 301 | + * Get a relative path including trailing slash, e.g. f/fa/ |
| 302 | + * If the repo is not hashed, returns an empty string |
| 303 | + */ |
| 304 | + function getHashPath( $name ) { |
| 305 | + if ( $this->isHashed() ) { |
| 306 | + $hash = md5( $name ); |
| 307 | + $path = ''; |
| 308 | + for ( $i = 1; $i <= $this->hashLevels; $i++ ) { |
| 309 | + $path .= substr( $hash, 0, $i ) . '/'; |
| 310 | + } |
| 311 | + return $path; |
| 312 | + } else { |
| 313 | + return ''; |
| 314 | + } |
| 315 | + } |
| 316 | + |
| 317 | + /** |
| 318 | + * Get the name of this repository, as specified by $info['name]' to the constructor |
| 319 | + */ |
| 320 | + function getName() { |
| 321 | + return $this->name; |
| 322 | + } |
| 323 | + |
| 324 | + /** |
| 325 | + * Get the file description page base URL, or false if there isn't one. |
| 326 | + * @private |
| 327 | + */ |
| 328 | + function getDescBaseUrl() { |
| 329 | + if ( is_null( $this->descBaseUrl ) ) { |
| 330 | + if ( !is_null( $this->articleUrl ) ) { |
| 331 | + $this->descBaseUrl = str_replace( '$1', |
| 332 | + urlencode( Namespace::getCanonicalName( NS_IMAGE ) ) . ':', $this->articleUrl ); |
| 333 | + } elseif ( !is_null( $this->scriptDirUrl ) ) { |
| 334 | + $this->descBaseUrl = $this->scriptDirUrl . '/index.php?title=' . |
| 335 | + urlencode( Namespace::getCanonicalName( NS_IMAGE ) ) . ':'; |
| 336 | + } else { |
| 337 | + $this->descBaseUrl = false; |
| 338 | + } |
| 339 | + } |
| 340 | + return $this->descBaseUrl; |
| 341 | + } |
| 342 | + |
| 343 | + /** |
| 344 | + * Get the URL of an image description page. May return false if it is |
| 345 | + * unknown or not applicable. In general this should only be called by the |
| 346 | + * File class, since it may return invalid results for certain kinds of |
| 347 | + * repositories. Use File::getDescriptionUrl() in user code. |
| 348 | + * |
| 349 | + * In particular, it uses the article paths as specified to the repository |
| 350 | + * constructor, whereas local repositories use the local Title functions. |
| 351 | + */ |
| 352 | + function getDescriptionUrl( $name ) { |
| 353 | + $base = $this->getDescBaseUrl(); |
| 354 | + if ( $base ) { |
| 355 | + return $base . wfUrlencode( $name ); |
| 356 | + } else { |
| 357 | + return false; |
| 358 | + } |
| 359 | + } |
| 360 | + |
| 361 | + /** |
| 362 | + * Get the URL of the content-only fragment of the description page. For |
| 363 | + * MediaWiki this means action=render. This should only be called by the |
| 364 | + * repository's file class, since it may return invalid results. User code |
| 365 | + * should use File::getDescriptionText(). |
| 366 | + */ |
| 367 | + function getDescriptionRenderUrl( $name ) { |
| 368 | + if ( isset( $this->scriptDirUrl ) ) { |
| 369 | + return $this->scriptDirUrl . '/index.php?title=' . |
| 370 | + wfUrlencode( Namespace::getCanonicalName( NS_IMAGE ) . ':' . $name ) . |
| 371 | + '&action=render'; |
| 372 | + } else { |
| 373 | + $descBase = $this->getDescBaseUrl(); |
| 374 | + if ( $descBase ) { |
| 375 | + return wfAppendQuery( $descBase . wfUrlencode( $name ), 'action=render' ); |
| 376 | + } else { |
| 377 | + return false; |
| 378 | + } |
| 379 | + } |
| 380 | + } |
| 381 | + |
| 382 | + /** |
| 383 | + * Call a callback function for every file in the repository. |
| 384 | + * Uses the filesystem even in child classes. |
| 385 | + */ |
| 386 | + function enumFilesInFS( $callback ) { |
| 387 | + $numDirs = 1 << ( $this->hashLevels * 4 ); |
| 388 | + for ( $flatIndex = 0; $flatIndex < $numDirs; $flatIndex++ ) { |
| 389 | + $hexString = sprintf( "%0{$this->hashLevels}x", $flatIndex ); |
| 390 | + $path = $this->directory; |
| 391 | + for ( $hexPos = 0; $hexPos < $this->hashLevels; $hexPos++ ) { |
| 392 | + $path .= '/' . substr( $hexString, 0, $hexPos + 1 ); |
| 393 | + } |
| 394 | + if ( !file_exists( $path ) || !is_dir( $path ) ) { |
| 395 | + continue; |
| 396 | + } |
| 397 | + $dir = opendir( $path ); |
| 398 | + while ( false !== ( $name = readdir( $dir ) ) ) { |
| 399 | + call_user_func( $callback, $path . '/' . $name ); |
| 400 | + } |
| 401 | + } |
| 402 | + } |
| 403 | + |
| 404 | + /** |
| 405 | + * Call a callaback function for every file in the repository |
| 406 | + * May use either the database or the filesystem |
| 407 | + */ |
| 408 | + function enumFiles( $callback ) { |
| 409 | + $this->enumFilesInFS( $callback ); |
| 410 | + } |
| 411 | +} |
| 412 | + |
| 413 | +?> |
Property changes on: branches/liquidthreads/includes/filerepo/FSRepo.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 414 | + native |
Index: branches/liquidthreads/includes/filerepo/File.php |
— | — | @@ -0,0 +1,989 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Base file class. Do not instantiate. |
| 6 | + * |
| 7 | + * Implements some public methods and some protected utility functions which |
| 8 | + * are required by multiple child classes. Contains stub functionality for |
| 9 | + * unimplemented public methods. |
| 10 | + * |
| 11 | + * Stub functions which should be overridden are marked with STUB. Some more |
| 12 | + * concrete functions are also typically overridden by child classes. |
| 13 | + * |
| 14 | + * Note that only the repo object knows what its file class is called. You should |
| 15 | + * never name a file class explictly outside of the repo class. Instead use the |
| 16 | + * repo's factory functions to generate file objects, for example: |
| 17 | + * |
| 18 | + * RepoGroup::singleton()->getLocalRepo()->newFile($title); |
| 19 | + * |
| 20 | + * The convenience functions wfLocalFile() and wfFindFile() should be sufficient |
| 21 | + * in most cases. |
| 22 | + * |
| 23 | + * @addtogroup FileRepo |
| 24 | + */ |
| 25 | +class File { |
| 26 | + const DELETED_FILE = 1; |
| 27 | + const DELETED_COMMENT = 2; |
| 28 | + const DELETED_USER = 4; |
| 29 | + const DELETED_RESTRICTED = 8; |
| 30 | + const RENDER_NOW = 1; |
| 31 | + |
| 32 | + const DELETE_SOURCE = 1; |
| 33 | + |
| 34 | + /** |
| 35 | + * Some member variables can be lazy-initialised using __get(). The |
| 36 | + * initialisation function for these variables is always a function named |
| 37 | + * like getVar(), where Var is the variable name with upper-case first |
| 38 | + * letter. |
| 39 | + * |
| 40 | + * The following variables are initialised in this way in this base class: |
| 41 | + * name, extension, handler, path, canRender, isSafeFile, |
| 42 | + * transformScript, hashPath, pageCount, url |
| 43 | + * |
| 44 | + * Code within this class should generally use the accessor function |
| 45 | + * directly, since __get() isn't re-entrant and therefore causes bugs that |
| 46 | + * depend on initialisation order. |
| 47 | + */ |
| 48 | + |
| 49 | + /** |
| 50 | + * The following member variables are not lazy-initialised |
| 51 | + */ |
| 52 | + var $repo, $title, $lastError; |
| 53 | + |
| 54 | + /** |
| 55 | + * Call this constructor from child classes |
| 56 | + */ |
| 57 | + function __construct( $title, $repo ) { |
| 58 | + $this->title = $title; |
| 59 | + $this->repo = $repo; |
| 60 | + } |
| 61 | + |
| 62 | + function __get( $name ) { |
| 63 | + $function = array( $this, 'get' . ucfirst( $name ) ); |
| 64 | + if ( !is_callable( $function ) ) { |
| 65 | + return null; |
| 66 | + } else { |
| 67 | + $this->$name = call_user_func( $function ); |
| 68 | + return $this->$name; |
| 69 | + } |
| 70 | + } |
| 71 | + |
| 72 | + /** |
| 73 | + * Normalize a file extension to the common form, and ensure it's clean. |
| 74 | + * Extensions with non-alphanumeric characters will be discarded. |
| 75 | + * |
| 76 | + * @param $ext string (without the .) |
| 77 | + * @return string |
| 78 | + */ |
| 79 | + static function normalizeExtension( $ext ) { |
| 80 | + $lower = strtolower( $ext ); |
| 81 | + $squish = array( |
| 82 | + 'htm' => 'html', |
| 83 | + 'jpeg' => 'jpg', |
| 84 | + 'mpeg' => 'mpg', |
| 85 | + 'tiff' => 'tif' ); |
| 86 | + if( isset( $squish[$lower] ) ) { |
| 87 | + return $squish[$lower]; |
| 88 | + } elseif( preg_match( '/^[0-9a-z]+$/', $lower ) ) { |
| 89 | + return $lower; |
| 90 | + } else { |
| 91 | + return ''; |
| 92 | + } |
| 93 | + } |
| 94 | + |
| 95 | + /** |
| 96 | + * Upgrade the database row if there is one |
| 97 | + * Called by ImagePage |
| 98 | + * STUB |
| 99 | + */ |
| 100 | + function upgradeRow() {} |
| 101 | + |
| 102 | + /** |
| 103 | + * Split an internet media type into its two components; if not |
| 104 | + * a two-part name, set the minor type to 'unknown'. |
| 105 | + * |
| 106 | + * @param $mime "text/html" etc |
| 107 | + * @return array ("text", "html") etc |
| 108 | + */ |
| 109 | + static function splitMime( $mime ) { |
| 110 | + if( strpos( $mime, '/' ) !== false ) { |
| 111 | + return explode( '/', $mime, 2 ); |
| 112 | + } else { |
| 113 | + return array( $mime, 'unknown' ); |
| 114 | + } |
| 115 | + } |
| 116 | + |
| 117 | + /** |
| 118 | + * Return the name of this file |
| 119 | + * @public |
| 120 | + */ |
| 121 | + function getName() { |
| 122 | + if ( !isset( $this->name ) ) { |
| 123 | + $this->name = $this->title->getDBkey(); |
| 124 | + } |
| 125 | + return $this->name; |
| 126 | + } |
| 127 | + |
| 128 | + /** |
| 129 | + * Get the file extension, e.g. "svg" |
| 130 | + */ |
| 131 | + function getExtension() { |
| 132 | + if ( !isset( $this->extension ) ) { |
| 133 | + $n = strrpos( $this->getName(), '.' ); |
| 134 | + $this->extension = self::normalizeExtension( |
| 135 | + $n ? substr( $this->getName(), $n + 1 ) : '' ); |
| 136 | + } |
| 137 | + return $this->extension; |
| 138 | + } |
| 139 | + |
| 140 | + /** |
| 141 | + * Return the associated title object |
| 142 | + * @public |
| 143 | + */ |
| 144 | + function getTitle() { return $this->title; } |
| 145 | + |
| 146 | + /** |
| 147 | + * Return the URL of the file |
| 148 | + * @public |
| 149 | + */ |
| 150 | + function getUrl() { |
| 151 | + if ( !isset( $this->url ) ) { |
| 152 | + $this->url = $this->repo->getZoneUrl( 'public' ) . '/' . $this->getUrlRel(); |
| 153 | + } |
| 154 | + return $this->url; |
| 155 | + } |
| 156 | + |
| 157 | + function getViewURL() { |
| 158 | + if( $this->mustRender()) { |
| 159 | + if( $this->canRender() ) { |
| 160 | + return $this->createThumb( $this->getWidth() ); |
| 161 | + } |
| 162 | + else { |
| 163 | + wfDebug(__METHOD__.': supposed to render '.$this->getName().' ('.$this->getMimeType()."), but can't!\n"); |
| 164 | + return $this->getURL(); #hm... return NULL? |
| 165 | + } |
| 166 | + } else { |
| 167 | + return $this->getURL(); |
| 168 | + } |
| 169 | + } |
| 170 | + |
| 171 | + /** |
| 172 | + * Return the full filesystem path to the file. Note that this does |
| 173 | + * not mean that a file actually exists under that location. |
| 174 | + * |
| 175 | + * This path depends on whether directory hashing is active or not, |
| 176 | + * i.e. whether the files are all found in the same directory, |
| 177 | + * or in hashed paths like /images/3/3c. |
| 178 | + * |
| 179 | + * May return false if the file is not locally accessible. |
| 180 | + * |
| 181 | + * @public |
| 182 | + */ |
| 183 | + function getPath() { |
| 184 | + if ( !isset( $this->path ) ) { |
| 185 | + $this->path = $this->repo->getZonePath('public') . '/' . $this->getRel(); |
| 186 | + } |
| 187 | + return $this->path; |
| 188 | + } |
| 189 | + |
| 190 | + /** |
| 191 | + * Alias for getPath() |
| 192 | + * @public |
| 193 | + */ |
| 194 | + function getFullPath() { |
| 195 | + return $this->getPath(); |
| 196 | + } |
| 197 | + |
| 198 | + /** |
| 199 | + * Return the width of the image. Returns false if the width is unknown |
| 200 | + * or undefined. |
| 201 | + * |
| 202 | + * STUB |
| 203 | + * Overridden by LocalFile, UnregisteredLocalFile |
| 204 | + * @public |
| 205 | + */ |
| 206 | + function getWidth( $page = 1 ) { return false; } |
| 207 | + |
| 208 | + /** |
| 209 | + * Return the height of the image. Returns false if the height is unknown |
| 210 | + * or undefined |
| 211 | + * |
| 212 | + * STUB |
| 213 | + * Overridden by LocalFile, UnregisteredLocalFile |
| 214 | + * @public |
| 215 | + */ |
| 216 | + function getHeight( $page = 1 ) { return false; } |
| 217 | + |
| 218 | + /** |
| 219 | + * Get handler-specific metadata |
| 220 | + * Overridden by LocalFile, UnregisteredLocalFile |
| 221 | + * STUB |
| 222 | + */ |
| 223 | + function getMetadata() { return false; } |
| 224 | + |
| 225 | + /** |
| 226 | + * Return the size of the image file, in bytes |
| 227 | + * Overridden by LocalFile, UnregisteredLocalFile |
| 228 | + * STUB |
| 229 | + * @public |
| 230 | + */ |
| 231 | + function getSize() { return false; } |
| 232 | + |
| 233 | + /** |
| 234 | + * Returns the mime type of the file. |
| 235 | + * Overridden by LocalFile, UnregisteredLocalFile |
| 236 | + * STUB |
| 237 | + */ |
| 238 | + function getMimeType() { return 'unknown/unknown'; } |
| 239 | + |
| 240 | + /** |
| 241 | + * Return the type of the media in the file. |
| 242 | + * Use the value returned by this function with the MEDIATYPE_xxx constants. |
| 243 | + * Overridden by LocalFile, |
| 244 | + * STUB |
| 245 | + */ |
| 246 | + function getMediaType() { return MEDIATYPE_UNKNOWN; } |
| 247 | + |
| 248 | + /** |
| 249 | + * Checks if the file can be presented to the browser as a bitmap. |
| 250 | + * |
| 251 | + * Currently, this checks if the file is an image format |
| 252 | + * that can be converted to a format |
| 253 | + * supported by all browsers (namely GIF, PNG and JPEG), |
| 254 | + * or if it is an SVG image and SVG conversion is enabled. |
| 255 | + */ |
| 256 | + function canRender() { |
| 257 | + if ( !isset( $this->canRender ) ) { |
| 258 | + $this->canRender = $this->getHandler() && $this->handler->canRender(); |
| 259 | + } |
| 260 | + return $this->canRender; |
| 261 | + } |
| 262 | + |
| 263 | + /** |
| 264 | + * Accessor for __get() |
| 265 | + */ |
| 266 | + protected function getCanRender() { |
| 267 | + return $this->canRender(); |
| 268 | + } |
| 269 | + |
| 270 | + /** |
| 271 | + * Return true if the file is of a type that can't be directly |
| 272 | + * rendered by typical browsers and needs to be re-rasterized. |
| 273 | + * |
| 274 | + * This returns true for everything but the bitmap types |
| 275 | + * supported by all browsers, i.e. JPEG; GIF and PNG. It will |
| 276 | + * also return true for any non-image formats. |
| 277 | + * |
| 278 | + * @return bool |
| 279 | + */ |
| 280 | + function mustRender() { |
| 281 | + return $this->getHandler() && $this->handler->mustRender(); |
| 282 | + } |
| 283 | + |
| 284 | + /** |
| 285 | + * Determines if this media file may be shown inline on a page. |
| 286 | + * |
| 287 | + * This is currently synonymous to canRender(), but this could be |
| 288 | + * extended to also allow inline display of other media, |
| 289 | + * like flash animations or videos. If you do so, please keep in mind that |
| 290 | + * that could be a security risk. |
| 291 | + */ |
| 292 | + function allowInlineDisplay() { |
| 293 | + return $this->canRender(); |
| 294 | + } |
| 295 | + |
| 296 | + /** |
| 297 | + * Determines if this media file is in a format that is unlikely to |
| 298 | + * contain viruses or malicious content. It uses the global |
| 299 | + * $wgTrustedMediaFormats list to determine if the file is safe. |
| 300 | + * |
| 301 | + * This is used to show a warning on the description page of non-safe files. |
| 302 | + * It may also be used to disallow direct [[media:...]] links to such files. |
| 303 | + * |
| 304 | + * Note that this function will always return true if allowInlineDisplay() |
| 305 | + * or isTrustedFile() is true for this file. |
| 306 | + */ |
| 307 | + function isSafeFile() { |
| 308 | + if ( !isset( $this->isSafeFile ) ) { |
| 309 | + $this->isSafeFile = $this->_getIsSafeFile(); |
| 310 | + } |
| 311 | + return $this->isSafeFile; |
| 312 | + } |
| 313 | + |
| 314 | + /** Accessor for __get() */ |
| 315 | + protected function getIsSafeFile() { |
| 316 | + return $this->isSafeFile(); |
| 317 | + } |
| 318 | + |
| 319 | + /** Uncached accessor */ |
| 320 | + protected function _getIsSafeFile() { |
| 321 | + if ($this->allowInlineDisplay()) return true; |
| 322 | + if ($this->isTrustedFile()) return true; |
| 323 | + |
| 324 | + global $wgTrustedMediaFormats; |
| 325 | + |
| 326 | + $type= $this->getMediaType(); |
| 327 | + $mime= $this->getMimeType(); |
| 328 | + #wfDebug("LocalFile::isSafeFile: type= $type, mime= $mime\n"); |
| 329 | + |
| 330 | + if (!$type || $type===MEDIATYPE_UNKNOWN) return false; #unknown type, not trusted |
| 331 | + if ( in_array( $type, $wgTrustedMediaFormats) ) return true; |
| 332 | + |
| 333 | + if ($mime==="unknown/unknown") return false; #unknown type, not trusted |
| 334 | + if ( in_array( $mime, $wgTrustedMediaFormats) ) return true; |
| 335 | + |
| 336 | + return false; |
| 337 | + } |
| 338 | + |
| 339 | + /** Returns true if the file is flagged as trusted. Files flagged that way |
| 340 | + * can be linked to directly, even if that is not allowed for this type of |
| 341 | + * file normally. |
| 342 | + * |
| 343 | + * This is a dummy function right now and always returns false. It could be |
| 344 | + * implemented to extract a flag from the database. The trusted flag could be |
| 345 | + * set on upload, if the user has sufficient privileges, to bypass script- |
| 346 | + * and html-filters. It may even be coupled with cryptographics signatures |
| 347 | + * or such. |
| 348 | + */ |
| 349 | + function isTrustedFile() { |
| 350 | + #this could be implemented to check a flag in the databas, |
| 351 | + #look for signatures, etc |
| 352 | + return false; |
| 353 | + } |
| 354 | + |
| 355 | + /** |
| 356 | + * Returns true if file exists in the repository. |
| 357 | + * |
| 358 | + * Overridden by LocalFile to avoid unnecessary stat calls. |
| 359 | + * |
| 360 | + * @return boolean Whether file exists in the repository. |
| 361 | + * @public |
| 362 | + */ |
| 363 | + function exists() { |
| 364 | + return $this->getPath() && file_exists( $this->path ); |
| 365 | + } |
| 366 | + |
| 367 | + function getTransformScript() { |
| 368 | + if ( !isset( $this->transformScript ) ) { |
| 369 | + $this->transformScript = false; |
| 370 | + if ( $this->repo ) { |
| 371 | + $script = $this->repo->getThumbScriptUrl(); |
| 372 | + if ( $script ) { |
| 373 | + $this->transformScript = "$script?f=" . urlencode( $this->getName() ); |
| 374 | + } |
| 375 | + } |
| 376 | + } |
| 377 | + return $this->transformScript; |
| 378 | + } |
| 379 | + |
| 380 | + /** |
| 381 | + * Get a ThumbnailImage which is the same size as the source |
| 382 | + */ |
| 383 | + function getUnscaledThumb( $page = false ) { |
| 384 | + $width = $this->getWidth( $page ); |
| 385 | + if ( !$width ) { |
| 386 | + return $this->iconThumb(); |
| 387 | + } |
| 388 | + if ( $page ) { |
| 389 | + $params = array( |
| 390 | + 'page' => $page, |
| 391 | + 'width' => $this->getWidth( $page ) |
| 392 | + ); |
| 393 | + } else { |
| 394 | + $params = array( 'width' => $this->getWidth() ); |
| 395 | + } |
| 396 | + return $this->transform( $params ); |
| 397 | + } |
| 398 | + |
| 399 | + /** |
| 400 | + * Return the file name of a thumbnail with the specified parameters |
| 401 | + * |
| 402 | + * @param array $params Handler-specific parameters |
| 403 | + * @private |
| 404 | + */ |
| 405 | + function thumbName( $params ) { |
| 406 | + if ( !$this->getHandler() ) { |
| 407 | + return null; |
| 408 | + } |
| 409 | + $extension = $this->getExtension(); |
| 410 | + list( $thumbExt, $thumbMime ) = $this->handler->getThumbType( $extension, $this->getMimeType() ); |
| 411 | + $thumbName = $this->handler->makeParamString( $params ) . '-' . $this->getName(); |
| 412 | + if ( $thumbExt != $extension ) { |
| 413 | + $thumbName .= ".$thumbExt"; |
| 414 | + } |
| 415 | + return $thumbName; |
| 416 | + } |
| 417 | + |
| 418 | + /** |
| 419 | + * Create a thumbnail of the image having the specified width/height. |
| 420 | + * The thumbnail will not be created if the width is larger than the |
| 421 | + * image's width. Let the browser do the scaling in this case. |
| 422 | + * The thumbnail is stored on disk and is only computed if the thumbnail |
| 423 | + * file does not exist OR if it is older than the image. |
| 424 | + * Returns the URL. |
| 425 | + * |
| 426 | + * Keeps aspect ratio of original image. If both width and height are |
| 427 | + * specified, the generated image will be no bigger than width x height, |
| 428 | + * and will also have correct aspect ratio. |
| 429 | + * |
| 430 | + * @param integer $width maximum width of the generated thumbnail |
| 431 | + * @param integer $height maximum height of the image (optional) |
| 432 | + * @public |
| 433 | + */ |
| 434 | + function createThumb( $width, $height = -1 ) { |
| 435 | + $params = array( 'width' => $width ); |
| 436 | + if ( $height != -1 ) { |
| 437 | + $params['height'] = $height; |
| 438 | + } |
| 439 | + $thumb = $this->transform( $params ); |
| 440 | + if( is_null( $thumb ) || $thumb->isError() ) return ''; |
| 441 | + return $thumb->getUrl(); |
| 442 | + } |
| 443 | + |
| 444 | + /** |
| 445 | + * As createThumb, but returns a ThumbnailImage object. This can |
| 446 | + * provide access to the actual file, the real size of the thumb, |
| 447 | + * and can produce a convenient <img> tag for you. |
| 448 | + * |
| 449 | + * For non-image formats, this may return a filetype-specific icon. |
| 450 | + * |
| 451 | + * @param integer $width maximum width of the generated thumbnail |
| 452 | + * @param integer $height maximum height of the image (optional) |
| 453 | + * @param boolean $render True to render the thumbnail if it doesn't exist, |
| 454 | + * false to just return the URL |
| 455 | + * |
| 456 | + * @return ThumbnailImage or null on failure |
| 457 | + * @public |
| 458 | + * |
| 459 | + * @deprecated use transform() |
| 460 | + */ |
| 461 | + function getThumbnail( $width, $height=-1, $render = true ) { |
| 462 | + $params = array( 'width' => $width ); |
| 463 | + if ( $height != -1 ) { |
| 464 | + $params['height'] = $height; |
| 465 | + } |
| 466 | + $flags = $render ? self::RENDER_NOW : 0; |
| 467 | + return $this->transform( $params, $flags ); |
| 468 | + } |
| 469 | + |
| 470 | + /** |
| 471 | + * Transform a media file |
| 472 | + * |
| 473 | + * @param array $params An associative array of handler-specific parameters. Typical |
| 474 | + * keys are width, height and page. |
| 475 | + * @param integer $flags A bitfield, may contain self::RENDER_NOW to force rendering |
| 476 | + * @return MediaTransformOutput |
| 477 | + */ |
| 478 | + function transform( $params, $flags = 0 ) { |
| 479 | + global $wgUseSquid, $wgIgnoreImageErrors; |
| 480 | + |
| 481 | + wfProfileIn( __METHOD__ ); |
| 482 | + do { |
| 483 | + if ( !$this->getHandler() || !$this->handler->canRender() ) { |
| 484 | + // not a bitmap or renderable image, don't try. |
| 485 | + $thumb = $this->iconThumb(); |
| 486 | + break; |
| 487 | + } |
| 488 | + |
| 489 | + $script = $this->getTransformScript(); |
| 490 | + if ( $script && !($flags & self::RENDER_NOW) ) { |
| 491 | + // Use a script to transform on client request |
| 492 | + $thumb = $this->handler->getScriptedTransform( $this, $script, $params ); |
| 493 | + break; |
| 494 | + } |
| 495 | + |
| 496 | + $normalisedParams = $params; |
| 497 | + $this->handler->normaliseParams( $this, $normalisedParams ); |
| 498 | + $thumbName = $this->thumbName( $normalisedParams ); |
| 499 | + $thumbPath = $this->getThumbPath( $thumbName ); |
| 500 | + $thumbUrl = $this->getThumbUrl( $thumbName ); |
| 501 | + |
| 502 | + if ( $this->repo->canTransformVia404() && !($flags & self::RENDER_NOW ) ) { |
| 503 | + $thumb = $this->handler->getTransform( $this, $thumbPath, $thumbUrl, $params ); |
| 504 | + break; |
| 505 | + } |
| 506 | + |
| 507 | + wfDebug( "Doing stat for $thumbPath\n" ); |
| 508 | + $this->migrateThumbFile( $thumbName ); |
| 509 | + if ( file_exists( $thumbPath ) ) { |
| 510 | + $thumb = $this->handler->getTransform( $this, $thumbPath, $thumbUrl, $params ); |
| 511 | + break; |
| 512 | + } |
| 513 | + $thumb = $this->handler->doTransform( $this, $thumbPath, $thumbUrl, $params ); |
| 514 | + |
| 515 | + // Ignore errors if requested |
| 516 | + if ( !$thumb ) { |
| 517 | + $thumb = null; |
| 518 | + } elseif ( $thumb->isError() ) { |
| 519 | + $this->lastError = $thumb->toText(); |
| 520 | + if ( $wgIgnoreImageErrors && !($flags & self::RENDER_NOW) ) { |
| 521 | + $thumb = $this->handler->getTransform( $this, $thumbPath, $thumbUrl, $params ); |
| 522 | + } |
| 523 | + } |
| 524 | + |
| 525 | + if ( $wgUseSquid ) { |
| 526 | + wfPurgeSquidServers( array( $thumbUrl ) ); |
| 527 | + } |
| 528 | + } while (false); |
| 529 | + |
| 530 | + wfProfileOut( __METHOD__ ); |
| 531 | + return $thumb; |
| 532 | + } |
| 533 | + |
| 534 | + /** |
| 535 | + * Hook into transform() to allow migration of thumbnail files |
| 536 | + * STUB |
| 537 | + * Overridden by LocalFile |
| 538 | + */ |
| 539 | + function migrateThumbFile() {} |
| 540 | + |
| 541 | + /** |
| 542 | + * Get a MediaHandler instance for this file |
| 543 | + */ |
| 544 | + function getHandler() { |
| 545 | + if ( !isset( $this->handler ) ) { |
| 546 | + $this->handler = MediaHandler::getHandler( $this->getMimeType() ); |
| 547 | + } |
| 548 | + return $this->handler; |
| 549 | + } |
| 550 | + |
| 551 | + /** |
| 552 | + * Get a ThumbnailImage representing a file type icon |
| 553 | + * @return ThumbnailImage |
| 554 | + */ |
| 555 | + function iconThumb() { |
| 556 | + global $wgStylePath, $wgStyleDirectory; |
| 557 | + |
| 558 | + $try = array( 'fileicon-' . $this->getExtension() . '.png', 'fileicon.png' ); |
| 559 | + foreach( $try as $icon ) { |
| 560 | + $path = '/common/images/icons/' . $icon; |
| 561 | + $filepath = $wgStyleDirectory . $path; |
| 562 | + if( file_exists( $filepath ) ) { |
| 563 | + return new ThumbnailImage( $wgStylePath . $path, 120, 120 ); |
| 564 | + } |
| 565 | + } |
| 566 | + return null; |
| 567 | + } |
| 568 | + |
| 569 | + /** |
| 570 | + * Get last thumbnailing error. |
| 571 | + * Largely obsolete. |
| 572 | + */ |
| 573 | + function getLastError() { |
| 574 | + return $this->lastError; |
| 575 | + } |
| 576 | + |
| 577 | + /** |
| 578 | + * Get all thumbnail names previously generated for this file |
| 579 | + * STUB |
| 580 | + * Overridden by LocalFile |
| 581 | + */ |
| 582 | + function getThumbnails() { return array(); } |
| 583 | + |
| 584 | + /** |
| 585 | + * Purge shared caches such as thumbnails and DB data caching |
| 586 | + * STUB |
| 587 | + * Overridden by LocalFile |
| 588 | + */ |
| 589 | + function purgeCache( $archiveFiles = array() ) {} |
| 590 | + |
| 591 | + /** |
| 592 | + * Purge the file description page, but don't go after |
| 593 | + * pages using the file. Use when modifying file history |
| 594 | + * but not the current data. |
| 595 | + */ |
| 596 | + function purgeDescription() { |
| 597 | + $title = $this->getTitle(); |
| 598 | + if ( $title ) { |
| 599 | + $title->invalidateCache(); |
| 600 | + $title->purgeSquid(); |
| 601 | + } |
| 602 | + } |
| 603 | + |
| 604 | + /** |
| 605 | + * Purge metadata and all affected pages when the file is created, |
| 606 | + * deleted, or majorly updated. A set of additional URLs may be |
| 607 | + * passed to purge, such as specific file files which have changed. |
| 608 | + * @param $urlArray array |
| 609 | + */ |
| 610 | + function purgeEverything( $urlArr=array() ) { |
| 611 | + // Delete thumbnails and refresh file metadata cache |
| 612 | + $this->purgeCache(); |
| 613 | + $this->purgeDescription(); |
| 614 | + |
| 615 | + // Purge cache of all pages using this file |
| 616 | + $title = $this->getTitle(); |
| 617 | + if ( $title ) { |
| 618 | + $update = new HTMLCacheUpdate( $title, 'imagelinks' ); |
| 619 | + $update->doUpdate(); |
| 620 | + } |
| 621 | + } |
| 622 | + |
| 623 | + /** |
| 624 | + * Return the history of this file, line by line. Starts with current version, |
| 625 | + * then old versions. Should return an object similar to an image/oldimage |
| 626 | + * database row. |
| 627 | + * |
| 628 | + * @public |
| 629 | + * STUB |
| 630 | + * Overridden in LocalFile |
| 631 | + */ |
| 632 | + function nextHistoryLine() { |
| 633 | + return false; |
| 634 | + } |
| 635 | + |
| 636 | + /** |
| 637 | + * Reset the history pointer to the first element of the history |
| 638 | + * @public |
| 639 | + * STUB |
| 640 | + * Overridden in LocalFile. |
| 641 | + */ |
| 642 | + function resetHistory() {} |
| 643 | + |
| 644 | + /** |
| 645 | + * Get the filename hash component of the directory including trailing slash, |
| 646 | + * e.g. f/fa/ |
| 647 | + * If the repository is not hashed, returns an empty string. |
| 648 | + */ |
| 649 | + function getHashPath() { |
| 650 | + if ( !isset( $this->hashPath ) ) { |
| 651 | + $this->hashPath = $this->repo->getHashPath( $this->getName() ); |
| 652 | + } |
| 653 | + return $this->hashPath; |
| 654 | + } |
| 655 | + |
| 656 | + /** |
| 657 | + * Get the path of the file relative to the public zone root |
| 658 | + */ |
| 659 | + function getRel() { |
| 660 | + return $this->getHashPath() . $this->getName(); |
| 661 | + } |
| 662 | + |
| 663 | + /** |
| 664 | + * Get urlencoded relative path of the file |
| 665 | + */ |
| 666 | + function getUrlRel() { |
| 667 | + return $this->getHashPath() . urlencode( $this->getName() ); |
| 668 | + } |
| 669 | + |
| 670 | + /** Get the path of the archive directory, or a particular file if $suffix is specified */ |
| 671 | + function getArchivePath( $suffix = false ) { |
| 672 | + $path = $this->repo->getZonePath('public') . '/archive/' . $this->getHashPath(); |
| 673 | + if ( $suffix !== false ) { |
| 674 | + $path .= '/' . $suffix; |
| 675 | + } |
| 676 | + return $path; |
| 677 | + } |
| 678 | + |
| 679 | + /** Get the path of the thumbnail directory, or a particular file if $suffix is specified */ |
| 680 | + function getThumbPath( $suffix = false ) { |
| 681 | + $path = $this->repo->getZonePath('public') . '/thumb/' . $this->getRel(); |
| 682 | + if ( $suffix !== false ) { |
| 683 | + $path .= '/' . $suffix; |
| 684 | + } |
| 685 | + return $path; |
| 686 | + } |
| 687 | + |
| 688 | + /** Get the URL of the archive directory, or a particular file if $suffix is specified */ |
| 689 | + function getArchiveUrl( $suffix = false ) { |
| 690 | + $path = $this->repo->getZoneUrl('public') . '/archive/' . $this->getHashPath(); |
| 691 | + if ( $suffix !== false ) { |
| 692 | + $path .= '/' . urlencode( $suffix ); |
| 693 | + } |
| 694 | + return $path; |
| 695 | + } |
| 696 | + |
| 697 | + /** Get the URL of the thumbnail directory, or a particular file if $suffix is specified */ |
| 698 | + function getThumbUrl( $suffix = false ) { |
| 699 | + $path = $this->repo->getZoneUrl('public') . '/thumb/' . $this->getUrlRel(); |
| 700 | + if ( $suffix !== false ) { |
| 701 | + $path .= '/' . urlencode( $suffix ); |
| 702 | + } |
| 703 | + return $path; |
| 704 | + } |
| 705 | + |
| 706 | + /** Get the virtual URL for an archive file or directory */ |
| 707 | + function getArchiveVirtualUrl( $suffix = false ) { |
| 708 | + $path = $this->repo->getVirtualUrl() . '/public/archive/' . $this->getHashPath(); |
| 709 | + if ( $suffix !== false ) { |
| 710 | + $path .= '/' . urlencode( $suffix ); |
| 711 | + } |
| 712 | + return $path; |
| 713 | + } |
| 714 | + |
| 715 | + /** Get the virtual URL for a thumbnail file or directory */ |
| 716 | + function getThumbVirtualUrl( $suffix = false ) { |
| 717 | + $path = $this->repo->getVirtualUrl() . '/public/thumb/' . $this->getHashPath(); |
| 718 | + if ( $suffix !== false ) { |
| 719 | + $path .= '/' . urlencode( $suffix ); |
| 720 | + } |
| 721 | + return $path; |
| 722 | + } |
| 723 | + |
| 724 | + /** |
| 725 | + * @return bool |
| 726 | + */ |
| 727 | + function isHashed() { |
| 728 | + return $this->repo->isHashed(); |
| 729 | + } |
| 730 | + |
| 731 | + function readOnlyError() { |
| 732 | + throw new MWException( get_class($this) . ': write operations are not supported' ); |
| 733 | + } |
| 734 | + |
| 735 | + /** |
| 736 | + * Record a file upload in the upload log and the image table |
| 737 | + * STUB |
| 738 | + * Overridden by LocalFile |
| 739 | + */ |
| 740 | + function recordUpload( $oldver, $desc, $license = '', $copyStatus = '', $source = '', $watch = false ) { |
| 741 | + $this->readOnlyError(); |
| 742 | + } |
| 743 | + |
| 744 | + /** |
| 745 | + * Move or copy a file to its public location. If a file exists at the |
| 746 | + * destination, move it to an archive. Returns the archive name on success |
| 747 | + * or an empty string if it was a new file, and a wikitext-formatted |
| 748 | + * WikiError object on failure. |
| 749 | + * |
| 750 | + * The archive name should be passed through to recordUpload for database |
| 751 | + * registration. |
| 752 | + * |
| 753 | + * @param string $sourcePath Local filesystem path to the source image |
| 754 | + * @param integer $flags A bitwise combination of: |
| 755 | + * File::DELETE_SOURCE Delete the source file, i.e. move |
| 756 | + * rather than copy |
| 757 | + * @return The archive name on success or an empty string if it was a new |
| 758 | + * file, and a wikitext-formatted WikiError object on failure. |
| 759 | + * |
| 760 | + * STUB |
| 761 | + * Overridden by LocalFile |
| 762 | + */ |
| 763 | + function publish( $srcPath, $flags = 0 ) { |
| 764 | + $this->readOnlyError(); |
| 765 | + } |
| 766 | + |
| 767 | + /** |
| 768 | + * Get an array of Title objects which are articles which use this file |
| 769 | + * Also adds their IDs to the link cache |
| 770 | + * |
| 771 | + * This is mostly copied from Title::getLinksTo() |
| 772 | + * |
| 773 | + * @deprecated Use HTMLCacheUpdate, this function uses too much memory |
| 774 | + */ |
| 775 | + function getLinksTo( $options = '' ) { |
| 776 | + wfProfileIn( __METHOD__ ); |
| 777 | + |
| 778 | + // Note: use local DB not repo DB, we want to know local links |
| 779 | + if ( $options ) { |
| 780 | + $db = wfGetDB( DB_MASTER ); |
| 781 | + } else { |
| 782 | + $db = wfGetDB( DB_SLAVE ); |
| 783 | + } |
| 784 | + $linkCache =& LinkCache::singleton(); |
| 785 | + |
| 786 | + list( $page, $imagelinks ) = $db->tableNamesN( 'page', 'imagelinks' ); |
| 787 | + $encName = $db->addQuotes( $this->getName() ); |
| 788 | + $sql = "SELECT page_namespace,page_title,page_id FROM $page,$imagelinks WHERE page_id=il_from AND il_to=$encName $options"; |
| 789 | + $res = $db->query( $sql, __METHOD__ ); |
| 790 | + |
| 791 | + $retVal = array(); |
| 792 | + if ( $db->numRows( $res ) ) { |
| 793 | + while ( $row = $db->fetchObject( $res ) ) { |
| 794 | + if ( $titleObj = Title::makeTitle( $row->page_namespace, $row->page_title ) ) { |
| 795 | + $linkCache->addGoodLinkObj( $row->page_id, $titleObj ); |
| 796 | + $retVal[] = $titleObj; |
| 797 | + } |
| 798 | + } |
| 799 | + } |
| 800 | + $db->freeResult( $res ); |
| 801 | + wfProfileOut( __METHOD__ ); |
| 802 | + return $retVal; |
| 803 | + } |
| 804 | + |
| 805 | + function getExifData() { |
| 806 | + if ( !$this->getHandler() || $this->handler->getMetadataType( $this ) != 'exif' ) { |
| 807 | + return array(); |
| 808 | + } |
| 809 | + $metadata = $this->getMetadata(); |
| 810 | + if ( !$metadata ) { |
| 811 | + return array(); |
| 812 | + } |
| 813 | + $exif = unserialize( $metadata ); |
| 814 | + if ( !$exif ) { |
| 815 | + return array(); |
| 816 | + } |
| 817 | + unset( $exif['MEDIAWIKI_EXIF_VERSION'] ); |
| 818 | + $format = new FormatExif( $exif ); |
| 819 | + |
| 820 | + return $format->getFormattedData(); |
| 821 | + } |
| 822 | + |
| 823 | + /** |
| 824 | + * Returns true if the file comes from the local file repository. |
| 825 | + * |
| 826 | + * @return bool |
| 827 | + */ |
| 828 | + function isLocal() { |
| 829 | + return $this->repo && $this->repo->getName() == 'local'; |
| 830 | + } |
| 831 | + |
| 832 | + /** |
| 833 | + * Returns true if the image is an old version |
| 834 | + * STUB |
| 835 | + */ |
| 836 | + function isOld() { |
| 837 | + return false; |
| 838 | + } |
| 839 | + |
| 840 | + /** |
| 841 | + * Is this file a "deleted" file in a private archive? |
| 842 | + * STUB |
| 843 | + */ |
| 844 | + function isDeleted( $field ) { |
| 845 | + return false; |
| 846 | + } |
| 847 | + |
| 848 | + /** |
| 849 | + * Was this file ever deleted from the wiki? |
| 850 | + * |
| 851 | + * @return bool |
| 852 | + */ |
| 853 | + function wasDeleted() { |
| 854 | + $title = $this->getTitle(); |
| 855 | + return $title && $title->isDeleted() > 0; |
| 856 | + } |
| 857 | + |
| 858 | + /** |
| 859 | + * Delete all versions of the file. |
| 860 | + * |
| 861 | + * Moves the files into an archive directory (or deletes them) |
| 862 | + * and removes the database rows. |
| 863 | + * |
| 864 | + * Cache purging is done; logging is caller's responsibility. |
| 865 | + * |
| 866 | + * @param $reason |
| 867 | + * @return true on success, false on some kind of failure |
| 868 | + * STUB |
| 869 | + * Overridden by LocalFile |
| 870 | + */ |
| 871 | + function delete( $reason, $suppress=false ) { |
| 872 | + $this->readOnlyError(); |
| 873 | + } |
| 874 | + |
| 875 | + /** |
| 876 | + * Restore all or specified deleted revisions to the given file. |
| 877 | + * Permissions and logging are left to the caller. |
| 878 | + * |
| 879 | + * May throw database exceptions on error. |
| 880 | + * |
| 881 | + * @param $versions set of record ids of deleted items to restore, |
| 882 | + * or empty to restore all revisions. |
| 883 | + * @return the number of file revisions restored if successful, |
| 884 | + * or false on failure |
| 885 | + * STUB |
| 886 | + * Overridden by LocalFile |
| 887 | + */ |
| 888 | + function restore( $versions=array(), $Unsuppress=false ) { |
| 889 | + $this->readOnlyError(); |
| 890 | + } |
| 891 | + |
| 892 | + /** |
| 893 | + * Returns 'true' if this image is a multipage document, e.g. a DJVU |
| 894 | + * document. |
| 895 | + * |
| 896 | + * @return Bool |
| 897 | + */ |
| 898 | + function isMultipage() { |
| 899 | + return $this->getHandler() && $this->handler->isMultiPage(); |
| 900 | + } |
| 901 | + |
| 902 | + /** |
| 903 | + * Returns the number of pages of a multipage document, or NULL for |
| 904 | + * documents which aren't multipage documents |
| 905 | + */ |
| 906 | + function pageCount() { |
| 907 | + if ( !isset( $this->pageCount ) ) { |
| 908 | + if ( $this->getHandler() && $this->handler->isMultiPage() ) { |
| 909 | + $this->pageCount = $this->handler->pageCount( $this ); |
| 910 | + } else { |
| 911 | + $this->pageCount = false; |
| 912 | + } |
| 913 | + } |
| 914 | + return $this->pageCount; |
| 915 | + } |
| 916 | + |
| 917 | + /** |
| 918 | + * Calculate the height of a thumbnail using the source and destination width |
| 919 | + */ |
| 920 | + static function scaleHeight( $srcWidth, $srcHeight, $dstWidth ) { |
| 921 | + // Exact integer multiply followed by division |
| 922 | + if ( $srcWidth == 0 ) { |
| 923 | + return 0; |
| 924 | + } else { |
| 925 | + return round( $srcHeight * $dstWidth / $srcWidth ); |
| 926 | + } |
| 927 | + } |
| 928 | + |
| 929 | + /** |
| 930 | + * Get an image size array like that returned by getimagesize(), or false if it |
| 931 | + * can't be determined. |
| 932 | + * |
| 933 | + * @param string $fileName The filename |
| 934 | + * @return array |
| 935 | + */ |
| 936 | + function getImageSize( $fileName ) { |
| 937 | + if ( !$this->getHandler() ) { |
| 938 | + return false; |
| 939 | + } |
| 940 | + return $this->handler->getImageSize( $this, $fileName ); |
| 941 | + } |
| 942 | + |
| 943 | + /** |
| 944 | + * Get the URL of the image description page. May return false if it is |
| 945 | + * unknown or not applicable. |
| 946 | + */ |
| 947 | + function getDescriptionUrl() { |
| 948 | + return $this->repo->getDescriptionUrl( $this->getName() ); |
| 949 | + } |
| 950 | + |
| 951 | + /** |
| 952 | + * Get the HTML text of the description page, if available |
| 953 | + */ |
| 954 | + function getDescriptionText() { |
| 955 | + if ( !$this->repo->fetchDescription ) { |
| 956 | + return false; |
| 957 | + } |
| 958 | + $renderUrl = $this->repo->getDescriptionRenderUrl( $this->getName() ); |
| 959 | + if ( $renderUrl ) { |
| 960 | + wfDebug( "Fetching shared description from $renderUrl\n" ); |
| 961 | + return Http::get( $renderUrl ); |
| 962 | + } else { |
| 963 | + return false; |
| 964 | + } |
| 965 | + } |
| 966 | + |
| 967 | + /** |
| 968 | + * Get the 14-character timestamp of the file upload, or false if |
| 969 | + */ |
| 970 | + function getTimestmap() { |
| 971 | + $path = $this->getPath(); |
| 972 | + if ( !file_exists( $path ) ) { |
| 973 | + return false; |
| 974 | + } |
| 975 | + return wfTimestamp( filemtime( $path ) ); |
| 976 | + } |
| 977 | + |
| 978 | + /** |
| 979 | + * Determine if the current user is allowed to view a particular |
| 980 | + * field of this file, if it's marked as deleted. |
| 981 | + * STUB |
| 982 | + * @param int $field |
| 983 | + * @return bool |
| 984 | + */ |
| 985 | + function userCan( $field ) { |
| 986 | + return true; |
| 987 | + } |
| 988 | +} |
| 989 | + |
| 990 | +?> |
Property changes on: branches/liquidthreads/includes/filerepo/File.php |
___________________________________________________________________ |
Added: svn:keywords |
1 | 991 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 992 | + native |
Index: branches/liquidthreads/includes/filerepo/ForeignDBFile.php |
— | — | @@ -0,0 +1,39 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class ForeignDBFile extends LocalFile { |
| 5 | + function newFromTitle( $title, $repo ) { |
| 6 | + return new self( $title, $repo ); |
| 7 | + } |
| 8 | + |
| 9 | + function getCacheKey() { |
| 10 | + if ( $this->repo->hasSharedCache ) { |
| 11 | + $hashedName = md5($this->name); |
| 12 | + return wfForeignMemcKey( $this->repo->dbName, $this->repo->tablePrefix, |
| 13 | + 'file', $hashedName ); |
| 14 | + } else { |
| 15 | + return false; |
| 16 | + } |
| 17 | + } |
| 18 | + |
| 19 | + function publish( /*...*/ ) { |
| 20 | + $this->readOnlyError(); |
| 21 | + } |
| 22 | + |
| 23 | + function recordUpload( /*...*/ ) { |
| 24 | + $this->readOnlyError(); |
| 25 | + } |
| 26 | + function restore( /*...*/ ) { |
| 27 | + $this->readOnlyError(); |
| 28 | + } |
| 29 | + |
| 30 | + function getDescriptionUrl() { |
| 31 | + // Restore remote behaviour |
| 32 | + return File::getDescriptionUrl(); |
| 33 | + } |
| 34 | + |
| 35 | + function getDescriptionText() { |
| 36 | + // Restore remote behaviour |
| 37 | + return File::getDescriptionText(); |
| 38 | + } |
| 39 | +} |
| 40 | +?> |
Property changes on: branches/liquidthreads/includes/filerepo/ForeignDBFile.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 41 | + native |
Index: branches/liquidthreads/includes/filerepo/LocalRepo.php |
— | — | @@ -0,0 +1,31 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * A repository that stores files in the local filesystem and registers them |
| 5 | + * in the wiki's own database. This is the most commonly used repository class. |
| 6 | + */ |
| 7 | +class LocalRepo extends FSRepo { |
| 8 | + var $fileFactory = array( 'LocalFile', 'newFromTitle' ); |
| 9 | + var $oldFileFactory = array( 'OldLocalFile', 'newFromTitle' ); |
| 10 | + |
| 11 | + function getSlaveDB() { |
| 12 | + return wfGetDB( DB_SLAVE ); |
| 13 | + } |
| 14 | + |
| 15 | + function getMasterDB() { |
| 16 | + return wfGetDB( DB_MASTER ); |
| 17 | + } |
| 18 | + |
| 19 | + function newFileFromRow( $row ) { |
| 20 | + if ( isset( $row->img_name ) ) { |
| 21 | + return LocalFile::newFromRow( $row, $this ); |
| 22 | + } elseif ( isset( $row->oi_name ) ) { |
| 23 | + return OldLocalFile::newFromRow( $row, $this ); |
| 24 | + } else { |
| 25 | + throw new MWException( __METHOD__.': invalid row' ); |
| 26 | + } |
| 27 | + } |
| 28 | + |
| 29 | + function newFromArchiveName( $title, $archiveName ) { |
| 30 | + return OldLocalFile::newFromArchiveName( $title, $this, $archiveName ); |
| 31 | + } |
| 32 | +} |
Property changes on: branches/liquidthreads/includes/filerepo/LocalRepo.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 33 | + native |
Index: branches/liquidthreads/includes/filerepo/RepoGroup.php |
— | — | @@ -0,0 +1,113 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Prioritized list of file repositories |
| 6 | + * @addtogroup filerepo |
| 7 | + */ |
| 8 | +class RepoGroup { |
| 9 | + var $localRepo, $foreignRepos, $reposInitialised = false; |
| 10 | + var $localInfo, $foreignInfo; |
| 11 | + |
| 12 | + protected static $instance; |
| 13 | + |
| 14 | + /** |
| 15 | + * Get a RepoGroup instance. At present only one instance of RepoGroup is |
| 16 | + * needed in a MediaWiki invocation, this may change in the future. |
| 17 | + */ |
| 18 | + function singleton() { |
| 19 | + if ( self::$instance ) { |
| 20 | + return self::$instance; |
| 21 | + } |
| 22 | + global $wgLocalFileRepo, $wgForeignFileRepos; |
| 23 | + self::$instance = new RepoGroup( $wgLocalFileRepo, $wgForeignFileRepos ); |
| 24 | + return self::$instance; |
| 25 | + } |
| 26 | + |
| 27 | + /** |
| 28 | + * Construct a group of file repositories. |
| 29 | + * @param array $data Array of repository info arrays. |
| 30 | + * Each info array is an associative array with the 'class' member |
| 31 | + * giving the class name. The entire array is passed to the repository |
| 32 | + * constructor as the first parameter. |
| 33 | + */ |
| 34 | + function __construct( $localInfo, $foreignInfo ) { |
| 35 | + $this->localInfo = $localInfo; |
| 36 | + $this->foreignInfo = $foreignInfo; |
| 37 | + } |
| 38 | + |
| 39 | + /** |
| 40 | + * Search repositories for an image. |
| 41 | + * You can also use wfGetFile() to do this. |
| 42 | + * @param mixed $title Title object or string |
| 43 | + * @param mixed $time The 14-char timestamp before which the file should |
| 44 | + * have been uploaded, or false for the current version |
| 45 | + * @return File object or false if it is not found |
| 46 | + */ |
| 47 | + function findFile( $title, $time = false ) { |
| 48 | + if ( !$this->reposInitialised ) { |
| 49 | + $this->initialiseRepos(); |
| 50 | + } |
| 51 | + |
| 52 | + $image = $this->localRepo->findFile( $title, $time ); |
| 53 | + if ( $image ) { |
| 54 | + return $image; |
| 55 | + } |
| 56 | + foreach ( $this->foreignRepos as $repo ) { |
| 57 | + $image = $repo->findFile( $title, $time ); |
| 58 | + if ( $image ) { |
| 59 | + return $image; |
| 60 | + } |
| 61 | + } |
| 62 | + return false; |
| 63 | + } |
| 64 | + |
| 65 | + /** |
| 66 | + * Get the repo instance with a given key. |
| 67 | + */ |
| 68 | + function getRepo( $index ) { |
| 69 | + if ( !$this->reposInitialised ) { |
| 70 | + $this->initialiseRepos(); |
| 71 | + } |
| 72 | + if ( $index == 'local' ) { |
| 73 | + return $this->localRepo; |
| 74 | + } elseif ( isset( $this->foreignRepos[$index] ) ) { |
| 75 | + return $this->foreignRepos[$index]; |
| 76 | + } else { |
| 77 | + return false; |
| 78 | + } |
| 79 | + } |
| 80 | + |
| 81 | + /** |
| 82 | + * Get the local repository, i.e. the one corresponding to the local image |
| 83 | + * table. Files are typically uploaded to the local repository. |
| 84 | + */ |
| 85 | + function getLocalRepo() { |
| 86 | + return $this->getRepo( 'local' ); |
| 87 | + } |
| 88 | + |
| 89 | + /** |
| 90 | + * Initialise the $repos array |
| 91 | + */ |
| 92 | + function initialiseRepos() { |
| 93 | + if ( $this->reposInitialised ) { |
| 94 | + return; |
| 95 | + } |
| 96 | + $this->reposInitialised = true; |
| 97 | + |
| 98 | + $this->localRepo = $this->newRepo( $this->localInfo ); |
| 99 | + $this->foreignRepos = array(); |
| 100 | + foreach ( $this->foreignInfo as $key => $info ) { |
| 101 | + $this->foreignRepos[$key] = $this->newRepo( $info ); |
| 102 | + } |
| 103 | + } |
| 104 | + |
| 105 | + /** |
| 106 | + * Create a repo class based on an info structure |
| 107 | + */ |
| 108 | + protected function newRepo( $info ) { |
| 109 | + $class = $info['class']; |
| 110 | + return new $class( $info ); |
| 111 | + } |
| 112 | +} |
| 113 | + |
| 114 | +?> |
Property changes on: branches/liquidthreads/includes/filerepo/RepoGroup.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 115 | + native |
Index: branches/liquidthreads/includes/filerepo/ArchivedFile.php |
— | — | @@ -0,0 +1,108 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * @addtogroup Media |
| 6 | + */ |
| 7 | +class ArchivedFile |
| 8 | +{ |
| 9 | + /** |
| 10 | + * Returns a file object from the filearchive table |
| 11 | + * @param $title, the corresponding image page title |
| 12 | + * @param $id, the image id, a unique key |
| 13 | + * @param $key, optional storage key |
| 14 | + * @return ResultWrapper |
| 15 | + */ |
| 16 | + function ArchivedFile( $title, $id=0, $key='' ) { |
| 17 | + if( !is_object( $title ) ) { |
| 18 | + throw new MWException( 'ArchivedFile constructor given bogus title.' ); |
| 19 | + } |
| 20 | + $conds = ($id) ? "fa_id = $id" : "fa_storage_key = '$key'"; |
| 21 | + if( $title->getNamespace() == NS_IMAGE ) { |
| 22 | + $dbr = wfGetDB( DB_SLAVE ); |
| 23 | + $res = $dbr->select( 'filearchive', |
| 24 | + array( |
| 25 | + 'fa_id', |
| 26 | + 'fa_name', |
| 27 | + 'fa_storage_key', |
| 28 | + 'fa_storage_group', |
| 29 | + 'fa_size', |
| 30 | + 'fa_bits', |
| 31 | + 'fa_width', |
| 32 | + 'fa_height', |
| 33 | + 'fa_metadata', |
| 34 | + 'fa_media_type', |
| 35 | + 'fa_major_mime', |
| 36 | + 'fa_minor_mime', |
| 37 | + 'fa_description', |
| 38 | + 'fa_user', |
| 39 | + 'fa_user_text', |
| 40 | + 'fa_timestamp', |
| 41 | + 'fa_deleted' ), |
| 42 | + array( |
| 43 | + 'fa_name' => $title->getDbKey(), |
| 44 | + $conds ), |
| 45 | + __METHOD__, |
| 46 | + array( 'ORDER BY' => 'fa_timestamp DESC' ) ); |
| 47 | + |
| 48 | + if ( $dbr->numRows( $res ) == 0 ) { |
| 49 | + // this revision does not exist? |
| 50 | + return; |
| 51 | + } |
| 52 | + $ret = $dbr->resultObject( $res ); |
| 53 | + $row = $ret->fetchObject(); |
| 54 | + |
| 55 | + // initialize fields for filestore image object |
| 56 | + $this->mId = intval($row->fa_id); |
| 57 | + $this->mName = $row->fa_name; |
| 58 | + $this->mGroup = $row->fa_storage_group; |
| 59 | + $this->mKey = $row->fa_storage_key; |
| 60 | + $this->mSize = $row->fa_size; |
| 61 | + $this->mBits = $row->fa_bits; |
| 62 | + $this->mWidth = $row->fa_width; |
| 63 | + $this->mHeight = $row->fa_height; |
| 64 | + $this->mMetaData = $row->fa_metadata; |
| 65 | + $this->mMime = "$row->fa_major_mime/$row->fa_minor_mime"; |
| 66 | + $this->mType = $row->fa_media_type; |
| 67 | + $this->mDescription = $row->fa_description; |
| 68 | + $this->mUser = $row->fa_user; |
| 69 | + $this->mUserText = $row->fa_user_text; |
| 70 | + $this->mTimestamp = $row->fa_timestamp; |
| 71 | + $this->mDeleted = $row->fa_deleted; |
| 72 | + } else { |
| 73 | + throw new MWException( 'This title does not correspond to an image page.' ); |
| 74 | + return; |
| 75 | + } |
| 76 | + return true; |
| 77 | + } |
| 78 | + |
| 79 | + /** |
| 80 | + * int $field one of DELETED_* bitfield constants |
| 81 | + * for file or revision rows |
| 82 | + * @return bool |
| 83 | + */ |
| 84 | + function isDeleted( $field ) { |
| 85 | + return ($this->mDeleted & $field) == $field; |
| 86 | + } |
| 87 | + |
| 88 | + /** |
| 89 | + * Determine if the current user is allowed to view a particular |
| 90 | + * field of this FileStore image file, if it's marked as deleted. |
| 91 | + * @param int $field |
| 92 | + * @return bool |
| 93 | + */ |
| 94 | + function userCan( $field ) { |
| 95 | + if( isset($this->mDeleted) && ($this->mDeleted & $field) == $field ) { |
| 96 | + // images |
| 97 | + global $wgUser; |
| 98 | + $permission = ( $this->mDeleted & File::DELETED_RESTRICTED ) == File::DELETED_RESTRICTED |
| 99 | + ? 'hiderevision' |
| 100 | + : 'deleterevision'; |
| 101 | + wfDebug( "Checking for $permission due to $field match on $this->mDeleted\n" ); |
| 102 | + return $wgUser->isAllowed( $permission ); |
| 103 | + } else { |
| 104 | + return true; |
| 105 | + } |
| 106 | + } |
| 107 | +} |
| 108 | + |
| 109 | +?> |
Property changes on: branches/liquidthreads/includes/filerepo/ArchivedFile.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 110 | + native |
Index: branches/liquidthreads/includes/filerepo/ForeignDBRepo.php |
— | — | @@ -0,0 +1,51 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * A foreign repository with an accessible MediaWiki database |
| 6 | + */ |
| 7 | + |
| 8 | +class ForeignDBRepo extends LocalRepo { |
| 9 | + # Settings |
| 10 | + var $dbType, $dbServer, $dbUser, $dbPassword, $dbName, $dbFlags, |
| 11 | + $tablePrefix, $hasSharedCache; |
| 12 | + |
| 13 | + # Other stuff |
| 14 | + var $dbConn; |
| 15 | + var $fileFactory = array( 'ForeignDBFile', 'newFromTitle' ); |
| 16 | + |
| 17 | + function __construct( $info ) { |
| 18 | + parent::__construct( $info ); |
| 19 | + $this->dbType = $info['dbType']; |
| 20 | + $this->dbServer = $info['dbServer']; |
| 21 | + $this->dbUser = $info['dbUser']; |
| 22 | + $this->dbPassword = $info['dbPassword']; |
| 23 | + $this->dbName = $info['dbName']; |
| 24 | + $this->dbFlags = $info['dbFlags']; |
| 25 | + $this->tablePrefix = $info['tablePrefix']; |
| 26 | + $this->hasSharedCache = $info['hasSharedCache']; |
| 27 | + } |
| 28 | + |
| 29 | + function getMasterDB() { |
| 30 | + if ( !isset( $this->dbConn ) ) { |
| 31 | + $class = 'Database' . ucfirst( $this->dbType ); |
| 32 | + $this->dbConn = new $class( $this->dbServer, $this->dbUser, |
| 33 | + $this->dbPassword, $this->dbName, false, $this->dbFlags, |
| 34 | + $this->tablePrefix ); |
| 35 | + } |
| 36 | + return $this->dbConn; |
| 37 | + } |
| 38 | + |
| 39 | + function getSlaveDB() { |
| 40 | + return $this->getMasterDB(); |
| 41 | + } |
| 42 | + |
| 43 | + function hasSharedCache() { |
| 44 | + return $this->hasSharedCache; |
| 45 | + } |
| 46 | + |
| 47 | + function store( /*...*/ ) { |
| 48 | + throw new MWException( get_class($this) . ': write operations are not supported' ); |
| 49 | + } |
| 50 | +} |
| 51 | + |
| 52 | +?> |
Property changes on: branches/liquidthreads/includes/filerepo/ForeignDBRepo.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 53 | + native |
Index: branches/liquidthreads/includes/filerepo/OldLocalFile.php |
— | — | @@ -0,0 +1,222 @@ |
| 2 | +<?php
|
| 3 | +
|
| 4 | +/**
|
| 5 | + * Class to represent a file in the oldimage table
|
| 6 | + *
|
| 7 | + * @addtogroup FileRepo
|
| 8 | + */
|
| 9 | +class OldLocalFile extends LocalFile {
|
| 10 | + var $requestedTime, $archive_name;
|
| 11 | +
|
| 12 | + const CACHE_VERSION = 1;
|
| 13 | + const MAX_CACHE_ROWS = 20;
|
| 14 | +
|
| 15 | + function newFromTitle( $title, $repo, $time ) {
|
| 16 | + return new self( $title, $repo, $time, null );
|
| 17 | + }
|
| 18 | +
|
| 19 | + function newFromArchiveName( $title, $repo, $archiveName ) {
|
| 20 | + return new self( $title, $repo, null, $archiveName );
|
| 21 | + }
|
| 22 | +
|
| 23 | + function newFromRow( $row, $repo ) {
|
| 24 | + $title = Title::makeTitle( NS_IMAGE, $row->oi_name );
|
| 25 | + $file = new self( $title, $repo, null, $row->oi_archive_name );
|
| 26 | + $file->loadFromRow( $row, 'oi_' );
|
| 27 | + return $file;
|
| 28 | + }
|
| 29 | +
|
| 30 | + /**
|
| 31 | + * @param Title $title
|
| 32 | + * @param FileRepo $repo
|
| 33 | + * @param string $time Timestamp or null to load by archive name
|
| 34 | + * @param string $archiveName Archive name or null to load by timestamp
|
| 35 | + */
|
| 36 | + function __construct( $title, $repo, $time, $archiveName ) {
|
| 37 | + parent::__construct( $title, $repo );
|
| 38 | + $this->requestedTime = $time;
|
| 39 | + $this->archive_name = $archiveName;
|
| 40 | + if ( is_null( $time ) && is_null( $archiveName ) ) {
|
| 41 | + throw new MWException( __METHOD__.': must specify at least one of $time or $archiveName' );
|
| 42 | + }
|
| 43 | + }
|
| 44 | +
|
| 45 | + function getCacheKey() {
|
| 46 | + $hashedName = md5($this->getName());
|
| 47 | + return wfMemcKey( 'oldfile', $hashedName );
|
| 48 | + }
|
| 49 | +
|
| 50 | + function getArchiveName() {
|
| 51 | + if ( !isset( $this->archive_name ) ) {
|
| 52 | + $this->load();
|
| 53 | + }
|
| 54 | + return $this->archive_name;
|
| 55 | + }
|
| 56 | +
|
| 57 | + function isOld() {
|
| 58 | + return true;
|
| 59 | + }
|
| 60 | +
|
| 61 | + /**
|
| 62 | + * Try to load file metadata from memcached. Returns true on success.
|
| 63 | + */
|
| 64 | + function loadFromCache() {
|
| 65 | + global $wgMemc;
|
| 66 | + wfProfileIn( __METHOD__ );
|
| 67 | + $this->dataLoaded = false;
|
| 68 | + $key = $this->getCacheKey();
|
| 69 | + if ( !$key ) {
|
| 70 | + return false;
|
| 71 | + }
|
| 72 | + $oldImages = $wgMemc->get( $key );
|
| 73 | +
|
| 74 | + if ( isset( $oldImages['version'] ) && $oldImages['version'] == MW_OLDFILE_VERSION ) {
|
| 75 | + unset( $oldImages['version'] );
|
| 76 | + $more = isset( $oldImages['more'] );
|
| 77 | + unset( $oldImages['more'] );
|
| 78 | + $found = false;
|
| 79 | + if ( is_null( $this->requestedTime ) ) {
|
| 80 | + foreach ( $oldImages as $timestamp => $info ) {
|
| 81 | + if ( $info['archive_name'] == $this->archive_name ) {
|
| 82 | + $found = true;
|
| 83 | + break;
|
| 84 | + }
|
| 85 | + }
|
| 86 | + } else {
|
| 87 | + krsort( $oldImages );
|
| 88 | + foreach ( $oldImages as $timestamp => $info ) {
|
| 89 | + if ( $timestamp <= $this->requestedTime ) {
|
| 90 | + $found = true;
|
| 91 | + break;
|
| 92 | + }
|
| 93 | + }
|
| 94 | + }
|
| 95 | + if ( $found ) {
|
| 96 | + wfDebug( "Pulling file metadata from cache key {$key}[{$timestamp}]\n" );
|
| 97 | + $this->dataLoaded = true;
|
| 98 | + foreach ( $cachedValues as $name => $value ) {
|
| 99 | + $this->$name = $value;
|
| 100 | + }
|
| 101 | + } elseif ( $more ) {
|
| 102 | + wfDebug( "Cache key was truncated, oldimage row might be found in the database\n" );
|
| 103 | + } else {
|
| 104 | + wfDebug( "Image did not exist at the specified time.\n" );
|
| 105 | + $this->fileExists = false;
|
| 106 | + $this->dataLoaded = true;
|
| 107 | + }
|
| 108 | + }
|
| 109 | +
|
| 110 | + if ( $this->dataLoaded ) {
|
| 111 | + wfIncrStats( 'image_cache_hit' );
|
| 112 | + } else {
|
| 113 | + wfIncrStats( 'image_cache_miss' );
|
| 114 | + }
|
| 115 | +
|
| 116 | + wfProfileOut( __METHOD__ );
|
| 117 | + return $this->dataLoaded;
|
| 118 | + }
|
| 119 | +
|
| 120 | + function saveToCache() {
|
| 121 | + // Cache the entire history of the image (up to MAX_CACHE_ROWS).
|
| 122 | + // This is expensive, so we only do it if $wgMemc is real
|
| 123 | + global $wgMemc;
|
| 124 | + if ( $wgMemc instanceof FakeMemcachedClient ) {
|
| 125 | + return;
|
| 126 | + }
|
| 127 | + $key = $this->getCacheKey();
|
| 128 | + if ( !$key ) {
|
| 129 | + return;
|
| 130 | + }
|
| 131 | + wfProfileIn( __METHOD__ );
|
| 132 | +
|
| 133 | + $dbr = $this->repo->getSlaveDB();
|
| 134 | + $res = $dbr->select( 'oldimage', $this->getCacheFields(),
|
| 135 | + array( 'oi_name' => $this->getName() ), __METHOD__,
|
| 136 | + array(
|
| 137 | + 'LIMIT' => self::MAX_CACHE_ROWS + 1,
|
| 138 | + 'ORDER BY' => 'oi_timestamp DESC',
|
| 139 | + ));
|
| 140 | + $cache = array( 'version' => self::CACHE_VERSION );
|
| 141 | + $numRows = $dbr->numRows( $res );
|
| 142 | + if ( $numRows > self::MAX_CACHE_ROWS ) {
|
| 143 | + $cache['more'] = true;
|
| 144 | + $numRows--;
|
| 145 | + }
|
| 146 | + for ( $i = 0; $i < $numRows; $i++ ) {
|
| 147 | + $row = $dbr->fetchObject( $res );
|
| 148 | + $this->decodeRow( $row, 'oi_' );
|
| 149 | + $cache[$row->oi_timestamp] = $row;
|
| 150 | + }
|
| 151 | + $dbr->freeResult( $res );
|
| 152 | + $wgMemc->set( $key, $cache, 7*86400 /* 1 week */ );
|
| 153 | + wfProfileOut( __METHOD__ );
|
| 154 | + }
|
| 155 | +
|
| 156 | + function loadFromDB() {
|
| 157 | + wfProfileIn( __METHOD__ );
|
| 158 | + $dbr = $this->repo->getSlaveDB();
|
| 159 | + $conds = array( 'oi_name' => $this->getName() );
|
| 160 | + if ( is_null( $this->requestedTimestamp ) ) {
|
| 161 | + $conds['oi_archive_name'] = $this->archive_name;
|
| 162 | + } else {
|
| 163 | + $conds[] = 'oi_timestamp <= ' . $dbr->addQuotes( $this->requestedTimestamp );
|
| 164 | + }
|
| 165 | + $row = $dbr->selectRow( 'oldimage', $this->getCacheFields( 'oi_' ),
|
| 166 | + $conds, __METHOD__, array( 'ORDER BY' => 'oi_timestamp DESC' ) );
|
| 167 | + if ( $row ) {
|
| 168 | + $this->loadFromRow( $row, 'oi_' );
|
| 169 | + } else {
|
| 170 | + $this->fileExists = false;
|
| 171 | + }
|
| 172 | + $this->dataLoaded = true;
|
| 173 | + }
|
| 174 | +
|
| 175 | + function getCacheFields( $prefix = 'img_' ) {
|
| 176 | + $fields = parent::getCacheFields( $prefix );
|
| 177 | + $fields[] = $prefix . 'archive_name';
|
| 178 | +
|
| 179 | + // XXX: Temporary hack before schema update
|
| 180 | + $fields = array_diff( $fields, array(
|
| 181 | + 'oi_media_type', 'oi_major_mime', 'oi_minor_mime', 'oi_metadata' ) );
|
| 182 | + return $fields;
|
| 183 | + }
|
| 184 | +
|
| 185 | + function getRel() {
|
| 186 | + return 'archive/' . $this->getHashPath() . $this->getArchiveName();
|
| 187 | + }
|
| 188 | +
|
| 189 | + function getUrlRel() {
|
| 190 | + return 'archive/' . $this->getHashPath() . urlencode( $this->getArchiveName() );
|
| 191 | + }
|
| 192 | +
|
| 193 | + function upgradeRow() {
|
| 194 | + wfProfileIn( __METHOD__ );
|
| 195 | +
|
| 196 | + $this->loadFromFile();
|
| 197 | +
|
| 198 | + $dbw = $this->repo->getMasterDB();
|
| 199 | + list( $major, $minor ) = self::splitMime( $this->mime );
|
| 200 | +
|
| 201 | + wfDebug(__METHOD__.': upgrading '.$this->archive_name." to the current schema\n");
|
| 202 | + $dbw->update( 'oldimage',
|
| 203 | + array(
|
| 204 | + 'oi_width' => $this->width,
|
| 205 | + 'oi_height' => $this->height,
|
| 206 | + 'oi_bits' => $this->bits,
|
| 207 | + #'oi_media_type' => $this->media_type,
|
| 208 | + #'oi_major_mime' => $major,
|
| 209 | + #'oi_minor_mime' => $minor,
|
| 210 | + #'oi_metadata' => $this->metadata,
|
| 211 | + ), array( 'oi_name' => $this->getName(), 'oi_timestamp' => $this->requestedTime ),
|
| 212 | + __METHOD__
|
| 213 | + );
|
| 214 | + wfProfileOut( __METHOD__ );
|
| 215 | + }
|
| 216 | +
|
| 217 | + // XXX: Temporary hack before schema update
|
| 218 | + function maybeUpgradeRow() {}
|
| 219 | +
|
| 220 | +}
|
| 221 | +
|
| 222 | +
|
| 223 | +?>
|
Index: branches/liquidthreads/includes/filerepo/LocalFile.php |
— | — | @@ -0,0 +1,1352 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + */ |
| 5 | + |
| 6 | +/** |
| 7 | + * Bump this number when serialized cache records may be incompatible. |
| 8 | + */ |
| 9 | +define( 'MW_FILE_VERSION', 4 ); |
| 10 | + |
| 11 | +/** |
| 12 | + * Class to represent a local file in the wiki's own database |
| 13 | + * |
| 14 | + * Provides methods to retrieve paths (physical, logical, URL), |
| 15 | + * to generate image thumbnails or for uploading. |
| 16 | + * |
| 17 | + * Note that only the repo object knows what its file class is called. You should |
| 18 | + * never name a file class explictly outside of the repo class. Instead use the |
| 19 | + * repo's factory functions to generate file objects, for example: |
| 20 | + * |
| 21 | + * RepoGroup::singleton()->getLocalRepo()->newFile($title); |
| 22 | + * |
| 23 | + * The convenience functions wfLocalFile() and wfFindFile() should be sufficient |
| 24 | + * in most cases. |
| 25 | + * |
| 26 | + * @addtogroup FileRepo |
| 27 | + */ |
| 28 | +class LocalFile extends File |
| 29 | +{ |
| 30 | + /**#@+ |
| 31 | + * @private |
| 32 | + */ |
| 33 | + var $fileExists, # does the file file exist on disk? (loadFromXxx) |
| 34 | + $historyLine, # Number of line to return by nextHistoryLine() (constructor) |
| 35 | + $historyRes, # result of the query for the file's history (nextHistoryLine) |
| 36 | + $width, # \ |
| 37 | + $height, # | |
| 38 | + $bits, # --- returned by getimagesize (loadFromXxx) |
| 39 | + $attr, # / |
| 40 | + $media_type, # MEDIATYPE_xxx (bitmap, drawing, audio...) |
| 41 | + $mime, # MIME type, determined by MimeMagic::guessMimeType |
| 42 | + $major_mime, # Major mime type |
| 43 | + $minor_mine, # Minor mime type |
| 44 | + $size, # Size in bytes (loadFromXxx) |
| 45 | + $metadata, # Metadata |
| 46 | + $timestamp, # Upload timestamp |
| 47 | + $dataLoaded, # Whether or not all this has been loaded from the database (loadFromXxx) |
| 48 | + $upgraded; # Whether the row was upgraded on load |
| 49 | + |
| 50 | + /**#@-*/ |
| 51 | + |
| 52 | + /** |
| 53 | + * Create a LocalFile from a title |
| 54 | + * Do not call this except from inside a repo class. |
| 55 | + */ |
| 56 | + function newFromTitle( $title, $repo ) { |
| 57 | + return new self( $title, $repo ); |
| 58 | + } |
| 59 | + |
| 60 | + /** |
| 61 | + * Create a LocalFile from a title |
| 62 | + * Do not call this except from inside a repo class. |
| 63 | + */ |
| 64 | + function newFromRow( $row, $repo ) { |
| 65 | + $title = Title::makeTitle( NS_IMAGE, $row->img_name ); |
| 66 | + $file = new self( $title, $repo ); |
| 67 | + $file->loadFromRow( $row ); |
| 68 | + return $file; |
| 69 | + } |
| 70 | + |
| 71 | + /** |
| 72 | + * Constructor. |
| 73 | + * Do not call this except from inside a repo class. |
| 74 | + */ |
| 75 | + function __construct( $title, $repo ) { |
| 76 | + if( !is_object( $title ) ) { |
| 77 | + throw new MWException( __CLASS__.' constructor given bogus title.' ); |
| 78 | + } |
| 79 | + parent::__construct( $title, $repo ); |
| 80 | + $this->metadata = ''; |
| 81 | + $this->historyLine = 0; |
| 82 | + $this->dataLoaded = false; |
| 83 | + } |
| 84 | + |
| 85 | + /** |
| 86 | + * Get the memcached key |
| 87 | + */ |
| 88 | + function getCacheKey() { |
| 89 | + $hashedName = md5($this->getName()); |
| 90 | + return wfMemcKey( 'file', $hashedName ); |
| 91 | + } |
| 92 | + |
| 93 | + /** |
| 94 | + * Try to load file metadata from memcached. Returns true on success. |
| 95 | + */ |
| 96 | + function loadFromCache() { |
| 97 | + global $wgMemc; |
| 98 | + wfProfileIn( __METHOD__ ); |
| 99 | + $this->dataLoaded = false; |
| 100 | + $key = $this->getCacheKey(); |
| 101 | + if ( !$key ) { |
| 102 | + return false; |
| 103 | + } |
| 104 | + $cachedValues = $wgMemc->get( $key ); |
| 105 | + |
| 106 | + // Check if the key existed and belongs to this version of MediaWiki |
| 107 | + if ( isset($cachedValues['version']) && ( $cachedValues['version'] == MW_FILE_VERSION ) ) { |
| 108 | + wfDebug( "Pulling file metadata from cache key $key\n" ); |
| 109 | + $this->fileExists = $cachedValues['fileExists']; |
| 110 | + if ( $this->fileExists ) { |
| 111 | + unset( $cachedValues['version'] ); |
| 112 | + unset( $cachedValues['fileExists'] ); |
| 113 | + foreach ( $cachedValues as $name => $value ) { |
| 114 | + $this->$name = $value; |
| 115 | + } |
| 116 | + } |
| 117 | + } |
| 118 | + if ( $this->dataLoaded ) { |
| 119 | + wfIncrStats( 'image_cache_hit' ); |
| 120 | + } else { |
| 121 | + wfIncrStats( 'image_cache_miss' ); |
| 122 | + } |
| 123 | + |
| 124 | + wfProfileOut( __METHOD__ ); |
| 125 | + return $this->dataLoaded; |
| 126 | + } |
| 127 | + |
| 128 | + /** |
| 129 | + * Save the file metadata to memcached |
| 130 | + */ |
| 131 | + function saveToCache() { |
| 132 | + global $wgMemc; |
| 133 | + $this->load(); |
| 134 | + $key = $this->getCacheKey(); |
| 135 | + if ( !$key ) { |
| 136 | + return; |
| 137 | + } |
| 138 | + $fields = $this->getCacheFields( '' ); |
| 139 | + $cache = array( 'version' => MW_FILE_VERSION ); |
| 140 | + $cache['fileExists'] = $this->fileExists; |
| 141 | + if ( $this->fileExists ) { |
| 142 | + foreach ( $fields as $field ) { |
| 143 | + $cache[$field] = $this->$field; |
| 144 | + } |
| 145 | + } |
| 146 | + |
| 147 | + $wgMemc->set( $key, $cache, 60 * 60 * 24 * 7 ); // A week |
| 148 | + } |
| 149 | + |
| 150 | + /** |
| 151 | + * Load metadata from the file itself |
| 152 | + */ |
| 153 | + function loadFromFile() { |
| 154 | + wfProfileIn( __METHOD__ ); |
| 155 | + $path = $this->getPath(); |
| 156 | + $this->fileExists = file_exists( $path ); |
| 157 | + $gis = array(); |
| 158 | + |
| 159 | + if ( $this->fileExists ) { |
| 160 | + $magic=& MimeMagic::singleton(); |
| 161 | + |
| 162 | + $this->mime = $magic->guessMimeType($path,true); |
| 163 | + list( $this->major_mime, $this->minor_mime ) = self::splitMime( $this->mime ); |
| 164 | + $this->media_type = $magic->getMediaType($path,$this->mime); |
| 165 | + $handler = MediaHandler::getHandler( $this->mime ); |
| 166 | + |
| 167 | + # Get size in bytes |
| 168 | + $this->size = filesize( $path ); |
| 169 | + |
| 170 | + # Height, width and metadata |
| 171 | + if ( $handler ) { |
| 172 | + $gis = $handler->getImageSize( $this, $path ); |
| 173 | + $this->metadata = $handler->getMetadata( $this, $path ); |
| 174 | + } else { |
| 175 | + $gis = false; |
| 176 | + $this->metadata = ''; |
| 177 | + } |
| 178 | + |
| 179 | + wfDebug(__METHOD__.": $path loaded, {$this->size} bytes, {$this->mime}.\n"); |
| 180 | + } else { |
| 181 | + $this->mime = NULL; |
| 182 | + $this->media_type = MEDIATYPE_UNKNOWN; |
| 183 | + $this->metadata = ''; |
| 184 | + wfDebug(__METHOD__.": $path NOT FOUND!\n"); |
| 185 | + } |
| 186 | + |
| 187 | + if( $gis ) { |
| 188 | + $this->width = $gis[0]; |
| 189 | + $this->height = $gis[1]; |
| 190 | + } else { |
| 191 | + $this->width = 0; |
| 192 | + $this->height = 0; |
| 193 | + } |
| 194 | + |
| 195 | + #NOTE: $gis[2] contains a code for the image type. This is no longer used. |
| 196 | + |
| 197 | + #NOTE: we have to set this flag early to avoid load() to be called |
| 198 | + # be some of the functions below. This may lead to recursion or other bad things! |
| 199 | + # as ther's only one thread of execution, this should be safe anyway. |
| 200 | + $this->dataLoaded = true; |
| 201 | + |
| 202 | + if ( isset( $gis['bits'] ) ) $this->bits = $gis['bits']; |
| 203 | + else $this->bits = 0; |
| 204 | + |
| 205 | + wfProfileOut( __METHOD__ ); |
| 206 | + } |
| 207 | + |
| 208 | + function getCacheFields( $prefix = 'img_' ) { |
| 209 | + static $fields = array( 'size', 'width', 'height', 'bits', 'media_type', |
| 210 | + 'major_mime', 'minor_mime', 'metadata', 'timestamp' ); |
| 211 | + static $results = array(); |
| 212 | + if ( $prefix == '' ) { |
| 213 | + return $fields; |
| 214 | + } |
| 215 | + if ( !isset( $results[$prefix] ) ) { |
| 216 | + $prefixedFields = array(); |
| 217 | + foreach ( $fields as $field ) { |
| 218 | + $prefixedFields[] = $prefix . $field; |
| 219 | + } |
| 220 | + $results[$prefix] = $prefixedFields; |
| 221 | + } |
| 222 | + return $results[$prefix]; |
| 223 | + } |
| 224 | + |
| 225 | + /** |
| 226 | + * Load file metadata from the DB |
| 227 | + */ |
| 228 | + function loadFromDB() { |
| 229 | + wfProfileIn( __METHOD__ ); |
| 230 | + |
| 231 | + # Unconditionally set loaded=true, we don't want the accessors constantly rechecking |
| 232 | + $this->dataLoaded = true; |
| 233 | + |
| 234 | + $dbr = $this->repo->getSlaveDB(); |
| 235 | + |
| 236 | + $row = $dbr->selectRow( 'image', $this->getCacheFields( 'img_' ), |
| 237 | + array( 'img_name' => $this->getName() ), __METHOD__ ); |
| 238 | + if ( $row ) { |
| 239 | + $this->loadFromRow( $row ); |
| 240 | + } else { |
| 241 | + $this->fileExists = false; |
| 242 | + } |
| 243 | + |
| 244 | + wfProfileOut( __METHOD__ ); |
| 245 | + } |
| 246 | + |
| 247 | + /** |
| 248 | + * Decode a row from the database (either object or array) to an array |
| 249 | + * with timestamps and MIME types decoded, and the field prefix removed. |
| 250 | + */ |
| 251 | + function decodeRow( $row, $prefix = 'img_' ) { |
| 252 | + $array = (array)$row; |
| 253 | + $prefixLength = strlen( $prefix ); |
| 254 | + // Sanity check prefix once |
| 255 | + if ( substr( key( $array ), 0, $prefixLength ) !== $prefix ) { |
| 256 | + throw new MWException( __METHOD__. ': incorrect $prefix parameter' ); |
| 257 | + } |
| 258 | + $decoded = array(); |
| 259 | + foreach ( $array as $name => $value ) { |
| 260 | + $deprefixedName = substr( $name, $prefixLength ); |
| 261 | + $decoded[substr( $name, $prefixLength )] = $value; |
| 262 | + } |
| 263 | + $decoded['timestamp'] = wfTimestamp( TS_MW, $decoded['timestamp'] ); |
| 264 | + if ( empty( $decoded['major_mime'] ) ) { |
| 265 | + $decoded['mime'] = "unknown/unknown"; |
| 266 | + } else { |
| 267 | + if (!$decoded['minor_mime']) { |
| 268 | + $decoded['minor_mime'] = "unknown"; |
| 269 | + } |
| 270 | + $decoded['mime'] = $decoded['major_mime'].'/'.$decoded['minor_mime']; |
| 271 | + } |
| 272 | + return $decoded; |
| 273 | + } |
| 274 | + |
| 275 | + /* |
| 276 | + * Load file metadata from a DB result row |
| 277 | + */ |
| 278 | + function loadFromRow( $row, $prefix = 'img_' ) { |
| 279 | + $array = $this->decodeRow( $row, $prefix ); |
| 280 | + foreach ( $array as $name => $value ) { |
| 281 | + $this->$name = $value; |
| 282 | + } |
| 283 | + $this->fileExists = true; |
| 284 | + // Check for rows from a previous schema, quietly upgrade them |
| 285 | + $this->maybeUpgradeRow(); |
| 286 | + } |
| 287 | + |
| 288 | + /** |
| 289 | + * Load file metadata from cache or DB, unless already loaded |
| 290 | + */ |
| 291 | + function load() { |
| 292 | + if ( !$this->dataLoaded ) { |
| 293 | + if ( !$this->loadFromCache() ) { |
| 294 | + $this->loadFromDB(); |
| 295 | + $this->saveToCache(); |
| 296 | + } |
| 297 | + $this->dataLoaded = true; |
| 298 | + } |
| 299 | + } |
| 300 | + |
| 301 | + /** |
| 302 | + * Upgrade a row if it needs it |
| 303 | + */ |
| 304 | + function maybeUpgradeRow() { |
| 305 | + if ( wfReadOnly() ) { |
| 306 | + return; |
| 307 | + } |
| 308 | + if ( is_null($this->media_type) || $this->mime == 'image/svg' ) { |
| 309 | + $this->upgradeRow(); |
| 310 | + $this->upgraded = true; |
| 311 | + } else { |
| 312 | + $handler = $this->getHandler(); |
| 313 | + if ( $handler && !$handler->isMetadataValid( $this, $this->metadata ) ) { |
| 314 | + $this->upgradeRow(); |
| 315 | + $this->upgraded = true; |
| 316 | + } |
| 317 | + } |
| 318 | + } |
| 319 | + |
| 320 | + function getUpgraded() { |
| 321 | + return $this->upgraded; |
| 322 | + } |
| 323 | + |
| 324 | + /** |
| 325 | + * Fix assorted version-related problems with the image row by reloading it from the file |
| 326 | + */ |
| 327 | + function upgradeRow() { |
| 328 | + wfProfileIn( __METHOD__ ); |
| 329 | + |
| 330 | + $this->loadFromFile(); |
| 331 | + |
| 332 | + $dbw = $this->repo->getMasterDB(); |
| 333 | + list( $major, $minor ) = self::splitMime( $this->mime ); |
| 334 | + |
| 335 | + wfDebug(__METHOD__.': upgrading '.$this->getName()." to the current schema\n"); |
| 336 | + |
| 337 | + $dbw->update( 'image', |
| 338 | + array( |
| 339 | + 'img_width' => $this->width, |
| 340 | + 'img_height' => $this->height, |
| 341 | + 'img_bits' => $this->bits, |
| 342 | + 'img_media_type' => $this->media_type, |
| 343 | + 'img_major_mime' => $major, |
| 344 | + 'img_minor_mime' => $minor, |
| 345 | + 'img_metadata' => $this->metadata, |
| 346 | + ), array( 'img_name' => $this->getName() ), |
| 347 | + __METHOD__ |
| 348 | + ); |
| 349 | + $this->saveToCache(); |
| 350 | + wfProfileOut( __METHOD__ ); |
| 351 | + } |
| 352 | + |
| 353 | + /** splitMime inherited */ |
| 354 | + /** getName inherited */ |
| 355 | + /** getTitle inherited */ |
| 356 | + /** getURL inherited */ |
| 357 | + /** getViewURL inherited */ |
| 358 | + /** getPath inherited */ |
| 359 | + |
| 360 | + /** |
| 361 | + * Return the width of the image |
| 362 | + * |
| 363 | + * Returns false on error |
| 364 | + * @public |
| 365 | + */ |
| 366 | + function getWidth( $page = 1 ) { |
| 367 | + $this->load(); |
| 368 | + if ( $this->isMultipage() ) { |
| 369 | + $dim = $this->getHandler()->getPageDimensions( $this, $page ); |
| 370 | + if ( $dim ) { |
| 371 | + return $dim['width']; |
| 372 | + } else { |
| 373 | + return false; |
| 374 | + } |
| 375 | + } else { |
| 376 | + return $this->width; |
| 377 | + } |
| 378 | + } |
| 379 | + |
| 380 | + /** |
| 381 | + * Return the height of the image |
| 382 | + * |
| 383 | + * Returns false on error |
| 384 | + * @public |
| 385 | + */ |
| 386 | + function getHeight( $page = 1 ) { |
| 387 | + $this->load(); |
| 388 | + if ( $this->isMultipage() ) { |
| 389 | + $dim = $this->getHandler()->getPageDimensions( $this, $page ); |
| 390 | + if ( $dim ) { |
| 391 | + return $dim['height']; |
| 392 | + } else { |
| 393 | + return false; |
| 394 | + } |
| 395 | + } else { |
| 396 | + return $this->height; |
| 397 | + } |
| 398 | + } |
| 399 | + |
| 400 | + /** |
| 401 | + * Get handler-specific metadata |
| 402 | + */ |
| 403 | + function getMetadata() { |
| 404 | + $this->load(); |
| 405 | + return $this->metadata; |
| 406 | + } |
| 407 | + |
| 408 | + /** |
| 409 | + * Return the size of the image file, in bytes |
| 410 | + * @public |
| 411 | + */ |
| 412 | + function getSize() { |
| 413 | + $this->load(); |
| 414 | + return $this->size; |
| 415 | + } |
| 416 | + |
| 417 | + /** |
| 418 | + * Returns the mime type of the file. |
| 419 | + */ |
| 420 | + function getMimeType() { |
| 421 | + $this->load(); |
| 422 | + return $this->mime; |
| 423 | + } |
| 424 | + |
| 425 | + /** |
| 426 | + * Return the type of the media in the file. |
| 427 | + * Use the value returned by this function with the MEDIATYPE_xxx constants. |
| 428 | + */ |
| 429 | + function getMediaType() { |
| 430 | + $this->load(); |
| 431 | + return $this->media_type; |
| 432 | + } |
| 433 | + |
| 434 | + /** canRender inherited */ |
| 435 | + /** mustRender inherited */ |
| 436 | + /** allowInlineDisplay inherited */ |
| 437 | + /** isSafeFile inherited */ |
| 438 | + /** isTrustedFile inherited */ |
| 439 | + |
| 440 | + /** |
| 441 | + * Returns true if the file file exists on disk. |
| 442 | + * @return boolean Whether file file exist on disk. |
| 443 | + * @public |
| 444 | + */ |
| 445 | + function exists() { |
| 446 | + $this->load(); |
| 447 | + return $this->fileExists; |
| 448 | + } |
| 449 | + |
| 450 | + /** getTransformScript inherited */ |
| 451 | + /** getUnscaledThumb inherited */ |
| 452 | + /** thumbName inherited */ |
| 453 | + /** createThumb inherited */ |
| 454 | + /** getThumbnail inherited */ |
| 455 | + /** transform inherited */ |
| 456 | + |
| 457 | + /** |
| 458 | + * Fix thumbnail files from 1.4 or before, with extreme prejudice |
| 459 | + */ |
| 460 | + function migrateThumbFile( $thumbName ) { |
| 461 | + $thumbDir = $this->getThumbPath(); |
| 462 | + $thumbPath = "$thumbDir/$thumbName"; |
| 463 | + if ( is_dir( $thumbPath ) ) { |
| 464 | + // Directory where file should be |
| 465 | + // This happened occasionally due to broken migration code in 1.5 |
| 466 | + // Rename to broken-* |
| 467 | + for ( $i = 0; $i < 100 ; $i++ ) { |
| 468 | + $broken = $this->repo->getZonePath('public') . "/broken-$i-$thumbName"; |
| 469 | + if ( !file_exists( $broken ) ) { |
| 470 | + rename( $thumbPath, $broken ); |
| 471 | + break; |
| 472 | + } |
| 473 | + } |
| 474 | + // Doesn't exist anymore |
| 475 | + clearstatcache(); |
| 476 | + } |
| 477 | + if ( is_file( $thumbDir ) ) { |
| 478 | + // File where directory should be |
| 479 | + unlink( $thumbDir ); |
| 480 | + // Doesn't exist anymore |
| 481 | + clearstatcache(); |
| 482 | + } |
| 483 | + } |
| 484 | + |
| 485 | + /** getHandler inherited */ |
| 486 | + /** iconThumb inherited */ |
| 487 | + /** getLastError inherited */ |
| 488 | + |
| 489 | + /** |
| 490 | + * Get all thumbnail names previously generated for this file |
| 491 | + */ |
| 492 | + function getThumbnails() { |
| 493 | + if ( $this->isHashed() ) { |
| 494 | + $this->load(); |
| 495 | + $files = array(); |
| 496 | + $dir = $this->getThumbPath(); |
| 497 | + |
| 498 | + if ( is_dir( $dir ) ) { |
| 499 | + $handle = opendir( $dir ); |
| 500 | + |
| 501 | + if ( $handle ) { |
| 502 | + while ( false !== ( $file = readdir($handle) ) ) { |
| 503 | + if ( $file{0} != '.' ) { |
| 504 | + $files[] = $file; |
| 505 | + } |
| 506 | + } |
| 507 | + closedir( $handle ); |
| 508 | + } |
| 509 | + } |
| 510 | + } else { |
| 511 | + $files = array(); |
| 512 | + } |
| 513 | + |
| 514 | + return $files; |
| 515 | + } |
| 516 | + |
| 517 | + /** |
| 518 | + * Refresh metadata in memcached, but don't touch thumbnails or squid |
| 519 | + */ |
| 520 | + function purgeMetadataCache() { |
| 521 | + clearstatcache(); |
| 522 | + $this->loadFromFile(); |
| 523 | + $this->saveToCache(); |
| 524 | + } |
| 525 | + |
| 526 | + /** |
| 527 | + * Delete all previously generated thumbnails, refresh metadata in memcached and purge the squid |
| 528 | + */ |
| 529 | + function purgeCache( $archiveFiles = array() ) { |
| 530 | + global $wgUseSquid; |
| 531 | + |
| 532 | + // Refresh metadata cache |
| 533 | + $this->purgeMetadataCache(); |
| 534 | + |
| 535 | + // Delete thumbnails |
| 536 | + $files = $this->getThumbnails(); |
| 537 | + $dir = $this->getThumbPath(); |
| 538 | + $urls = array(); |
| 539 | + foreach ( $files as $file ) { |
| 540 | + $m = array(); |
| 541 | + # Check that the base file name is part of the thumb name |
| 542 | + # This is a basic sanity check to avoid erasing unrelated directories |
| 543 | + if ( strpos( $file, $this->getName() ) !== false ) { |
| 544 | + $url = $this->getThumbUrl( $file ); |
| 545 | + $urls[] = $url; |
| 546 | + @unlink( "$dir/$file" ); |
| 547 | + } |
| 548 | + } |
| 549 | + |
| 550 | + // Purge the squid |
| 551 | + if ( $wgUseSquid ) { |
| 552 | + $urls[] = $this->getURL(); |
| 553 | + foreach ( $archiveFiles as $file ) { |
| 554 | + $urls[] = $this->getArchiveUrl( $file ); |
| 555 | + } |
| 556 | + wfPurgeSquidServers( $urls ); |
| 557 | + } |
| 558 | + } |
| 559 | + |
| 560 | + /** purgeDescription inherited */ |
| 561 | + /** purgeEverything inherited */ |
| 562 | + |
| 563 | + /** |
| 564 | + * Return the history of this file, line by line. |
| 565 | + * starts with current version, then old versions. |
| 566 | + * uses $this->historyLine to check which line to return: |
| 567 | + * 0 return line for current version |
| 568 | + * 1 query for old versions, return first one |
| 569 | + * 2, ... return next old version from above query |
| 570 | + * |
| 571 | + * @public |
| 572 | + */ |
| 573 | + function nextHistoryLine() { |
| 574 | + $dbr = $this->repo->getSlaveDB(); |
| 575 | + |
| 576 | + if ( $this->historyLine == 0 ) {// called for the first time, return line from cur |
| 577 | + $this->historyRes = $dbr->select( 'image', |
| 578 | + array( |
| 579 | + 'img_size', |
| 580 | + 'img_description', |
| 581 | + 'img_user','img_user_text', |
| 582 | + 'img_timestamp', |
| 583 | + 'img_width', |
| 584 | + 'img_height', |
| 585 | + "'' AS oi_archive_name" |
| 586 | + ), |
| 587 | + array( 'img_name' => $this->title->getDBkey() ), |
| 588 | + __METHOD__ |
| 589 | + ); |
| 590 | + if ( 0 == $dbr->numRows( $this->historyRes ) ) { |
| 591 | + return FALSE; |
| 592 | + } |
| 593 | + } else if ( $this->historyLine == 1 ) { |
| 594 | + $this->historyRes = $dbr->select( 'oldimage', |
| 595 | + array( |
| 596 | + 'oi_size AS img_size', |
| 597 | + 'oi_description AS img_description', |
| 598 | + 'oi_user AS img_user', |
| 599 | + 'oi_user_text AS img_user_text', |
| 600 | + 'oi_timestamp AS img_timestamp', |
| 601 | + 'oi_width as img_width', |
| 602 | + 'oi_height as img_height', |
| 603 | + 'oi_archive_name' |
| 604 | + ), |
| 605 | + array( 'oi_name' => $this->title->getDBkey() ), |
| 606 | + __METHOD__, |
| 607 | + array( 'ORDER BY' => 'oi_timestamp DESC' ) |
| 608 | + ); |
| 609 | + } |
| 610 | + $this->historyLine ++; |
| 611 | + |
| 612 | + return $dbr->fetchObject( $this->historyRes ); |
| 613 | + } |
| 614 | + |
| 615 | + /** |
| 616 | + * Reset the history pointer to the first element of the history |
| 617 | + * @public |
| 618 | + */ |
| 619 | + function resetHistory() { |
| 620 | + $this->historyLine = 0; |
| 621 | + } |
| 622 | + |
| 623 | + /** getFullPath inherited */ |
| 624 | + /** getHashPath inherited */ |
| 625 | + /** getRel inherited */ |
| 626 | + /** getUrlRel inherited */ |
| 627 | + /** getArchivePath inherited */ |
| 628 | + /** getThumbPath inherited */ |
| 629 | + /** getArchiveUrl inherited */ |
| 630 | + /** getThumbUrl inherited */ |
| 631 | + /** getArchiveVirtualUrl inherited */ |
| 632 | + /** getThumbVirtualUrl inherited */ |
| 633 | + /** isHashed inherited */ |
| 634 | + |
| 635 | + /** |
| 636 | + * Record a file upload in the upload log and the image table |
| 637 | + */ |
| 638 | + function recordUpload( $oldver, $desc, $license = '', $copyStatus = '', $source = '', |
| 639 | + $watch = false, $timestamp = false ) |
| 640 | + { |
| 641 | + global $wgUser, $wgUseCopyrightUpload; |
| 642 | + |
| 643 | + $dbw = $this->repo->getMasterDB(); |
| 644 | + |
| 645 | + // Delete thumbnails and refresh the metadata cache |
| 646 | + $this->purgeCache(); |
| 647 | + |
| 648 | + // Fail now if the file isn't there |
| 649 | + if ( !$this->fileExists ) { |
| 650 | + wfDebug( __METHOD__.": File ".$this->getPath()." went missing!\n" ); |
| 651 | + return false; |
| 652 | + } |
| 653 | + |
| 654 | + if ( $wgUseCopyrightUpload ) { |
| 655 | + if ( $license != '' ) { |
| 656 | + $licensetxt = '== ' . wfMsgForContent( 'license' ) . " ==\n" . '{{' . $license . '}}' . "\n"; |
| 657 | + } |
| 658 | + $textdesc = '== ' . wfMsg ( 'filedesc' ) . " ==\n" . $desc . "\n" . |
| 659 | + '== ' . wfMsgForContent ( 'filestatus' ) . " ==\n" . $copyStatus . "\n" . |
| 660 | + "$licensetxt" . |
| 661 | + '== ' . wfMsgForContent ( 'filesource' ) . " ==\n" . $source ; |
| 662 | + } else { |
| 663 | + if ( $license != '' ) { |
| 664 | + $filedesc = $desc == '' ? '' : '== ' . wfMsg ( 'filedesc' ) . " ==\n" . $desc . "\n"; |
| 665 | + $textdesc = $filedesc . |
| 666 | + '== ' . wfMsgForContent ( 'license' ) . " ==\n" . '{{' . $license . '}}' . "\n"; |
| 667 | + } else { |
| 668 | + $textdesc = $desc; |
| 669 | + } |
| 670 | + } |
| 671 | + |
| 672 | + if ( $timestamp === false ) { |
| 673 | + $timestamp = $dbw->timestamp(); |
| 674 | + } |
| 675 | + |
| 676 | + #split mime type |
| 677 | + if (strpos($this->mime,'/')!==false) { |
| 678 | + list($major,$minor)= explode('/',$this->mime,2); |
| 679 | + } |
| 680 | + else { |
| 681 | + $major= $this->mime; |
| 682 | + $minor= "unknown"; |
| 683 | + } |
| 684 | + |
| 685 | + # Test to see if the row exists using INSERT IGNORE |
| 686 | + # This avoids race conditions by locking the row until the commit, and also |
| 687 | + # doesn't deadlock. SELECT FOR UPDATE causes a deadlock for every race condition. |
| 688 | + $dbw->insert( 'image', |
| 689 | + array( |
| 690 | + 'img_name' => $this->getName(), |
| 691 | + 'img_size'=> $this->size, |
| 692 | + 'img_width' => intval( $this->width ), |
| 693 | + 'img_height' => intval( $this->height ), |
| 694 | + 'img_bits' => $this->bits, |
| 695 | + 'img_media_type' => $this->media_type, |
| 696 | + 'img_major_mime' => $major, |
| 697 | + 'img_minor_mime' => $minor, |
| 698 | + 'img_timestamp' => $timestamp, |
| 699 | + 'img_description' => $desc, |
| 700 | + 'img_user' => $wgUser->getID(), |
| 701 | + 'img_user_text' => $wgUser->getName(), |
| 702 | + 'img_metadata' => $this->metadata, |
| 703 | + ), |
| 704 | + __METHOD__, |
| 705 | + 'IGNORE' |
| 706 | + ); |
| 707 | + |
| 708 | + if( $dbw->affectedRows() == 0 ) { |
| 709 | + # Collision, this is an update of a file |
| 710 | + # Insert previous contents into oldimage |
| 711 | + $dbw->insertSelect( 'oldimage', 'image', |
| 712 | + array( |
| 713 | + 'oi_name' => 'img_name', |
| 714 | + 'oi_archive_name' => $dbw->addQuotes( $oldver ), |
| 715 | + 'oi_size' => 'img_size', |
| 716 | + 'oi_width' => 'img_width', |
| 717 | + 'oi_height' => 'img_height', |
| 718 | + 'oi_bits' => 'img_bits', |
| 719 | + 'oi_timestamp' => 'img_timestamp', |
| 720 | + 'oi_description' => 'img_description', |
| 721 | + 'oi_user' => 'img_user', |
| 722 | + 'oi_user_text' => 'img_user_text', |
| 723 | + ), array( 'img_name' => $this->getName() ), __METHOD__ |
| 724 | + ); |
| 725 | + |
| 726 | + # Update the current image row |
| 727 | + $dbw->update( 'image', |
| 728 | + array( /* SET */ |
| 729 | + 'img_size' => $this->size, |
| 730 | + 'img_width' => intval( $this->width ), |
| 731 | + 'img_height' => intval( $this->height ), |
| 732 | + 'img_bits' => $this->bits, |
| 733 | + 'img_media_type' => $this->media_type, |
| 734 | + 'img_major_mime' => $major, |
| 735 | + 'img_minor_mime' => $minor, |
| 736 | + 'img_timestamp' => $timestamp, |
| 737 | + 'img_description' => $desc, |
| 738 | + 'img_user' => $wgUser->getID(), |
| 739 | + 'img_user_text' => $wgUser->getName(), |
| 740 | + 'img_metadata' => $this->metadata, |
| 741 | + ), array( /* WHERE */ |
| 742 | + 'img_name' => $this->getName() |
| 743 | + ), __METHOD__ |
| 744 | + ); |
| 745 | + } else { |
| 746 | + # This is a new file |
| 747 | + # Update the image count |
| 748 | + $site_stats = $dbw->tableName( 'site_stats' ); |
| 749 | + $dbw->query( "UPDATE $site_stats SET ss_images=ss_images+1", __METHOD__ ); |
| 750 | + } |
| 751 | + |
| 752 | + $descTitle = $this->getTitle(); |
| 753 | + $article = new Article( $descTitle ); |
| 754 | + $minor = false; |
| 755 | + $watch = $watch || $wgUser->isWatched( $descTitle ); |
| 756 | + $suppressRC = true; // There's already a log entry, so don't double the RC load |
| 757 | + |
| 758 | + if( $descTitle->exists() ) { |
| 759 | + // TODO: insert a null revision into the page history for this update. |
| 760 | + if( $watch ) { |
| 761 | + $wgUser->addWatch( $descTitle ); |
| 762 | + } |
| 763 | + |
| 764 | + # Invalidate the cache for the description page |
| 765 | + $descTitle->invalidateCache(); |
| 766 | + $descTitle->purgeSquid(); |
| 767 | + } else { |
| 768 | + // New file; create the description page. |
| 769 | + $article->insertNewArticle( $textdesc, $desc, $minor, $watch, $suppressRC ); |
| 770 | + } |
| 771 | + |
| 772 | + # Hooks, hooks, the magic of hooks... |
| 773 | + wfRunHooks( 'FileUpload', array( $this ) ); |
| 774 | + |
| 775 | + # Add the log entry |
| 776 | + $log = new LogPage( 'upload' ); |
| 777 | + $log->addEntry( 'upload', $descTitle, $desc ); |
| 778 | + |
| 779 | + # Commit the transaction now, in case something goes wrong later |
| 780 | + # The most important thing is that files don't get lost, especially archives |
| 781 | + $dbw->immediateCommit(); |
| 782 | + |
| 783 | + # Invalidate cache for all pages using this file |
| 784 | + $update = new HTMLCacheUpdate( $this->getTitle(), 'imagelinks' ); |
| 785 | + $update->doUpdate(); |
| 786 | + |
| 787 | + return true; |
| 788 | + } |
| 789 | + |
| 790 | + /** |
| 791 | + * Move or copy a file to its public location. If a file exists at the |
| 792 | + * destination, move it to an archive. Returns the archive name on success |
| 793 | + * or an empty string if it was a new file, and a wikitext-formatted |
| 794 | + * WikiError object on failure. |
| 795 | + * |
| 796 | + * The archive name should be passed through to recordUpload for database |
| 797 | + * registration. |
| 798 | + * |
| 799 | + * @param string $sourcePath Local filesystem path to the source image |
| 800 | + * @param integer $flags A bitwise combination of: |
| 801 | + * File::DELETE_SOURCE Delete the source file, i.e. move |
| 802 | + * rather than copy |
| 803 | + * @return The archive name on success or an empty string if it was a new |
| 804 | + * file, and a wikitext-formatted WikiError object on failure. |
| 805 | + */ |
| 806 | + function publish( $srcPath, $flags = 0 ) { |
| 807 | + $dstPath = $this->getFullPath(); |
| 808 | + $archiveName = gmdate( 'YmdHis' ) . '!'. $this->getName(); |
| 809 | + $archivePath = $this->getArchivePath( $archiveName ); |
| 810 | + $flags = $flags & File::DELETE_SOURCE ? LocalRepo::DELETE_SOURCE : 0; |
| 811 | + $status = $this->repo->publish( $srcPath, $dstPath, $archivePath, $flags ); |
| 812 | + if ( WikiError::isError( $status ) ) { |
| 813 | + return $status; |
| 814 | + } elseif ( $status == 'new' ) { |
| 815 | + return ''; |
| 816 | + } else { |
| 817 | + return $archiveName; |
| 818 | + } |
| 819 | + } |
| 820 | + |
| 821 | + /** getLinksTo inherited */ |
| 822 | + /** getExifData inherited */ |
| 823 | + /** isLocal inherited */ |
| 824 | + /** wasDeleted inherited */ |
| 825 | + |
| 826 | + /** |
| 827 | + * Delete all versions of the file. |
| 828 | + * |
| 829 | + * Moves the files into an archive directory (or deletes them) |
| 830 | + * and removes the database rows. |
| 831 | + * |
| 832 | + * Cache purging is done; logging is caller's responsibility. |
| 833 | + * |
| 834 | + * @param $reason |
| 835 | + * @return true on success, false on some kind of failure |
| 836 | + */ |
| 837 | + function delete( $reason, $suppress=false ) { |
| 838 | + $transaction = new FSTransaction(); |
| 839 | + $urlArr = array( $this->getURL() ); |
| 840 | + |
| 841 | + if( !FileStore::lock() ) { |
| 842 | + wfDebug( __METHOD__.": failed to acquire file store lock, aborting\n" ); |
| 843 | + return false; |
| 844 | + } |
| 845 | + |
| 846 | + try { |
| 847 | + $dbw = $this->repo->getMasterDB(); |
| 848 | + $dbw->begin(); |
| 849 | + |
| 850 | + // Delete old versions |
| 851 | + $result = $dbw->select( 'oldimage', |
| 852 | + array( 'oi_archive_name' ), |
| 853 | + array( 'oi_name' => $this->getName() ) ); |
| 854 | + |
| 855 | + while( $row = $dbw->fetchObject( $result ) ) { |
| 856 | + $oldName = $row->oi_archive_name; |
| 857 | + |
| 858 | + $transaction->add( $this->prepareDeleteOld( $oldName, $reason, $suppress ) ); |
| 859 | + |
| 860 | + // We'll need to purge this URL from caches... |
| 861 | + $urlArr[] = $this->getArchiveUrl( $oldName ); |
| 862 | + } |
| 863 | + $dbw->freeResult( $result ); |
| 864 | + |
| 865 | + // And the current version... |
| 866 | + $transaction->add( $this->prepareDeleteCurrent( $reason, $suppress ) ); |
| 867 | + |
| 868 | + $dbw->immediateCommit(); |
| 869 | + } catch( MWException $e ) { |
| 870 | + wfDebug( __METHOD__.": db error, rolling back file transactions\n" ); |
| 871 | + $transaction->rollback(); |
| 872 | + FileStore::unlock(); |
| 873 | + throw $e; |
| 874 | + } |
| 875 | + |
| 876 | + wfDebug( __METHOD__.": deleted db items, applying file transactions\n" ); |
| 877 | + $transaction->commit(); |
| 878 | + FileStore::unlock(); |
| 879 | + |
| 880 | + |
| 881 | + // Update site_stats |
| 882 | + $site_stats = $dbw->tableName( 'site_stats' ); |
| 883 | + $dbw->query( "UPDATE $site_stats SET ss_images=ss_images-1", __METHOD__ ); |
| 884 | + |
| 885 | + $this->purgeEverything( $urlArr ); |
| 886 | + |
| 887 | + return true; |
| 888 | + } |
| 889 | + |
| 890 | + |
| 891 | + /** |
| 892 | + * Delete an old version of the file. |
| 893 | + * |
| 894 | + * Moves the file into an archive directory (or deletes it) |
| 895 | + * and removes the database row. |
| 896 | + * |
| 897 | + * Cache purging is done; logging is caller's responsibility. |
| 898 | + * |
| 899 | + * @param $reason |
| 900 | + * @throws MWException or FSException on database or filestore failure |
| 901 | + * @return true on success, false on some kind of failure |
| 902 | + */ |
| 903 | + function deleteOld( $archiveName, $reason, $suppress=false ) { |
| 904 | + $transaction = new FSTransaction(); |
| 905 | + $urlArr = array(); |
| 906 | + |
| 907 | + if( !FileStore::lock() ) { |
| 908 | + wfDebug( __METHOD__.": failed to acquire file store lock, aborting\n" ); |
| 909 | + return false; |
| 910 | + } |
| 911 | + |
| 912 | + $transaction = new FSTransaction(); |
| 913 | + try { |
| 914 | + $dbw = $this->repo->getMasterDB(); |
| 915 | + $dbw->begin(); |
| 916 | + $transaction->add( $this->prepareDeleteOld( $archiveName, $reason, $suppress ) ); |
| 917 | + $dbw->immediateCommit(); |
| 918 | + } catch( MWException $e ) { |
| 919 | + wfDebug( __METHOD__.": db error, rolling back file transaction\n" ); |
| 920 | + $transaction->rollback(); |
| 921 | + FileStore::unlock(); |
| 922 | + throw $e; |
| 923 | + } |
| 924 | + |
| 925 | + wfDebug( __METHOD__.": deleted db items, applying file transaction\n" ); |
| 926 | + $transaction->commit(); |
| 927 | + FileStore::unlock(); |
| 928 | + |
| 929 | + $this->purgeDescription(); |
| 930 | + |
| 931 | + // Squid purging |
| 932 | + global $wgUseSquid; |
| 933 | + if ( $wgUseSquid ) { |
| 934 | + $urlArr = array( |
| 935 | + $this->getArchiveUrl( $archiveName ), |
| 936 | + ); |
| 937 | + wfPurgeSquidServers( $urlArr ); |
| 938 | + } |
| 939 | + return true; |
| 940 | + } |
| 941 | + |
| 942 | + /** |
| 943 | + * Delete the current version of a file. |
| 944 | + * May throw a database error. |
| 945 | + * @return true on success, false on failure |
| 946 | + */ |
| 947 | + private function prepareDeleteCurrent( $reason, $suppress=false ) { |
| 948 | + return $this->prepareDeleteVersion( |
| 949 | + $this->getFullPath(), |
| 950 | + $reason, |
| 951 | + 'image', |
| 952 | + array( |
| 953 | + 'fa_name' => 'img_name', |
| 954 | + 'fa_archive_name' => 'NULL', |
| 955 | + 'fa_size' => 'img_size', |
| 956 | + 'fa_width' => 'img_width', |
| 957 | + 'fa_height' => 'img_height', |
| 958 | + 'fa_metadata' => 'img_metadata', |
| 959 | + 'fa_bits' => 'img_bits', |
| 960 | + 'fa_media_type' => 'img_media_type', |
| 961 | + 'fa_major_mime' => 'img_major_mime', |
| 962 | + 'fa_minor_mime' => 'img_minor_mime', |
| 963 | + 'fa_description' => 'img_description', |
| 964 | + 'fa_user' => 'img_user', |
| 965 | + 'fa_user_text' => 'img_user_text', |
| 966 | + 'fa_timestamp' => 'img_timestamp' ), |
| 967 | + array( 'img_name' => $this->getName() ), |
| 968 | + $suppress, |
| 969 | + __METHOD__ ); |
| 970 | + } |
| 971 | + |
| 972 | + /** |
| 973 | + * Delete a given older version of a file. |
| 974 | + * May throw a database error. |
| 975 | + * @return true on success, false on failure |
| 976 | + */ |
| 977 | + private function prepareDeleteOld( $archiveName, $reason, $suppress=false ) { |
| 978 | + $oldpath = $this->getArchivePath() . |
| 979 | + DIRECTORY_SEPARATOR . $archiveName; |
| 980 | + return $this->prepareDeleteVersion( |
| 981 | + $oldpath, |
| 982 | + $reason, |
| 983 | + 'oldimage', |
| 984 | + array( |
| 985 | + 'fa_name' => 'oi_name', |
| 986 | + 'fa_archive_name' => 'oi_archive_name', |
| 987 | + 'fa_size' => 'oi_size', |
| 988 | + 'fa_width' => 'oi_width', |
| 989 | + 'fa_height' => 'oi_height', |
| 990 | + 'fa_metadata' => 'NULL', |
| 991 | + 'fa_bits' => 'oi_bits', |
| 992 | + 'fa_media_type' => 'NULL', |
| 993 | + 'fa_major_mime' => 'NULL', |
| 994 | + 'fa_minor_mime' => 'NULL', |
| 995 | + 'fa_description' => 'oi_description', |
| 996 | + 'fa_user' => 'oi_user', |
| 997 | + 'fa_user_text' => 'oi_user_text', |
| 998 | + 'fa_timestamp' => 'oi_timestamp' ), |
| 999 | + array( |
| 1000 | + 'oi_name' => $this->getName(), |
| 1001 | + 'oi_archive_name' => $archiveName ), |
| 1002 | + $suppress, |
| 1003 | + __METHOD__ ); |
| 1004 | + } |
| 1005 | + |
| 1006 | + /** |
| 1007 | + * Do the dirty work of backing up an image row and its file |
| 1008 | + * (if $wgSaveDeletedFiles is on) and removing the originals. |
| 1009 | + * |
| 1010 | + * Must be run while the file store is locked and a database |
| 1011 | + * transaction is open to avoid race conditions. |
| 1012 | + * |
| 1013 | + * @return FSTransaction |
| 1014 | + */ |
| 1015 | + private function prepareDeleteVersion( $path, $reason, $table, $fieldMap, $where, $suppress=false, $fname ) { |
| 1016 | + global $wgUser, $wgSaveDeletedFiles; |
| 1017 | + |
| 1018 | + // Dupe the file into the file store |
| 1019 | + if( file_exists( $path ) ) { |
| 1020 | + if( $wgSaveDeletedFiles ) { |
| 1021 | + $group = 'deleted'; |
| 1022 | + |
| 1023 | + $store = FileStore::get( $group ); |
| 1024 | + $key = FileStore::calculateKey( $path, $this->getExtension() ); |
| 1025 | + $transaction = $store->insert( $key, $path, |
| 1026 | + FileStore::DELETE_ORIGINAL ); |
| 1027 | + } else { |
| 1028 | + $group = null; |
| 1029 | + $key = null; |
| 1030 | + $transaction = FileStore::deleteFile( $path ); |
| 1031 | + } |
| 1032 | + } else { |
| 1033 | + wfDebug( __METHOD__." deleting already-missing '$path'; moving on to database\n" ); |
| 1034 | + $group = null; |
| 1035 | + $key = null; |
| 1036 | + $transaction = new FSTransaction(); // empty |
| 1037 | + } |
| 1038 | + |
| 1039 | + if( $transaction === false ) { |
| 1040 | + // Fail to restore? |
| 1041 | + wfDebug( __METHOD__.": import to file store failed, aborting\n" ); |
| 1042 | + throw new MWException( "Could not archive and delete file $path" ); |
| 1043 | + return false; |
| 1044 | + } |
| 1045 | + |
| 1046 | + // Bitfields to further supress the file content |
| 1047 | + // Note that currently, live files are stored elsewhere |
| 1048 | + // and cannot be partially deleted |
| 1049 | + $bitfield = 0; |
| 1050 | + if ( $suppress ) { |
| 1051 | + $bitfield |= self::DELETED_FILE; |
| 1052 | + $bitfield |= self::DELETED_COMMENT; |
| 1053 | + $bitfield |= self::DELETED_USER; |
| 1054 | + $bitfield |= self::DELETED_RESTRICTED; |
| 1055 | + } |
| 1056 | + |
| 1057 | + $dbw = $this->repo->getMasterDB(); |
| 1058 | + $storageMap = array( |
| 1059 | + 'fa_storage_group' => $dbw->addQuotes( $group ), |
| 1060 | + 'fa_storage_key' => $dbw->addQuotes( $key ), |
| 1061 | + |
| 1062 | + 'fa_deleted_user' => $dbw->addQuotes( $wgUser->getId() ), |
| 1063 | + 'fa_deleted_timestamp' => $dbw->timestamp(), |
| 1064 | + 'fa_deleted_reason' => $dbw->addQuotes( $reason ), |
| 1065 | + 'fa_deleted' => $bitfield); |
| 1066 | + $allFields = array_merge( $storageMap, $fieldMap ); |
| 1067 | + |
| 1068 | + try { |
| 1069 | + if( $wgSaveDeletedFiles ) { |
| 1070 | + $dbw->insertSelect( 'filearchive', $table, $allFields, $where, $fname ); |
| 1071 | + } |
| 1072 | + $dbw->delete( $table, $where, $fname ); |
| 1073 | + } catch( DBQueryError $e ) { |
| 1074 | + // Something went horribly wrong! |
| 1075 | + // Leave the file as it was... |
| 1076 | + wfDebug( __METHOD__.": database error, rolling back file transaction\n" ); |
| 1077 | + $transaction->rollback(); |
| 1078 | + throw $e; |
| 1079 | + } |
| 1080 | + |
| 1081 | + return $transaction; |
| 1082 | + } |
| 1083 | + |
| 1084 | + /** |
| 1085 | + * Restore all or specified deleted revisions to the given file. |
| 1086 | + * Permissions and logging are left to the caller. |
| 1087 | + * |
| 1088 | + * May throw database exceptions on error. |
| 1089 | + * |
| 1090 | + * @param $versions set of record ids of deleted items to restore, |
| 1091 | + * or empty to restore all revisions. |
| 1092 | + * @return the number of file revisions restored if successful, |
| 1093 | + * or false on failure |
| 1094 | + */ |
| 1095 | + function restore( $versions=array(), $Unsuppress=false ) { |
| 1096 | + global $wgUser; |
| 1097 | + |
| 1098 | + if( !FileStore::lock() ) { |
| 1099 | + wfDebug( __METHOD__." could not acquire filestore lock\n" ); |
| 1100 | + return false; |
| 1101 | + } |
| 1102 | + |
| 1103 | + $transaction = new FSTransaction(); |
| 1104 | + try { |
| 1105 | + $dbw = $this->repo->getMasterDB(); |
| 1106 | + $dbw->begin(); |
| 1107 | + |
| 1108 | + // Re-confirm whether this file presently exists; |
| 1109 | + // if no we'll need to create an file record for the |
| 1110 | + // first item we restore. |
| 1111 | + $exists = $dbw->selectField( 'image', '1', |
| 1112 | + array( 'img_name' => $this->getName() ), |
| 1113 | + __METHOD__ ); |
| 1114 | + |
| 1115 | + // Fetch all or selected archived revisions for the file, |
| 1116 | + // sorted from the most recent to the oldest. |
| 1117 | + $conditions = array( 'fa_name' => $this->getName() ); |
| 1118 | + if( $versions ) { |
| 1119 | + $conditions['fa_id'] = $versions; |
| 1120 | + } |
| 1121 | + |
| 1122 | + $result = $dbw->select( 'filearchive', '*', |
| 1123 | + $conditions, |
| 1124 | + __METHOD__, |
| 1125 | + array( 'ORDER BY' => 'fa_timestamp DESC' ) ); |
| 1126 | + |
| 1127 | + if( $dbw->numRows( $result ) < count( $versions ) ) { |
| 1128 | + // There's some kind of conflict or confusion; |
| 1129 | + // we can't restore everything we were asked to. |
| 1130 | + wfDebug( __METHOD__.": couldn't find requested items\n" ); |
| 1131 | + $dbw->rollback(); |
| 1132 | + FileStore::unlock(); |
| 1133 | + return false; |
| 1134 | + } |
| 1135 | + |
| 1136 | + if( $dbw->numRows( $result ) == 0 ) { |
| 1137 | + // Nothing to do. |
| 1138 | + wfDebug( __METHOD__.": nothing to do\n" ); |
| 1139 | + $dbw->rollback(); |
| 1140 | + FileStore::unlock(); |
| 1141 | + return true; |
| 1142 | + } |
| 1143 | + |
| 1144 | + $revisions = 0; |
| 1145 | + while( $row = $dbw->fetchObject( $result ) ) { |
| 1146 | + if ( $Unsuppress ) { |
| 1147 | + // Currently, fa_deleted flags fall off upon restore, lets be careful about this |
| 1148 | + } else if ( ($row->fa_deleted & Revision::DELETED_RESTRICTED) && !$wgUser->isAllowed('hiderevision') ) { |
| 1149 | + // Skip restoring file revisions that the user cannot restore |
| 1150 | + continue; |
| 1151 | + } |
| 1152 | + $revisions++; |
| 1153 | + $store = FileStore::get( $row->fa_storage_group ); |
| 1154 | + if( !$store ) { |
| 1155 | + wfDebug( __METHOD__.": skipping row with no file.\n" ); |
| 1156 | + continue; |
| 1157 | + } |
| 1158 | + |
| 1159 | + $restoredImage = new self( Title::makeTitle( NS_IMAGE, $row->fa_name ), $this->repo ); |
| 1160 | + |
| 1161 | + if( $revisions == 1 && !$exists ) { |
| 1162 | + $destPath = $restoredImage->getFullPath(); |
| 1163 | + $destDir = dirname( $destPath ); |
| 1164 | + if ( !is_dir( $destDir ) ) { |
| 1165 | + wfMkdirParents( $destDir ); |
| 1166 | + } |
| 1167 | + |
| 1168 | + // We may have to fill in data if this was originally |
| 1169 | + // an archived file revision. |
| 1170 | + if( is_null( $row->fa_metadata ) ) { |
| 1171 | + $tempFile = $store->filePath( $row->fa_storage_key ); |
| 1172 | + |
| 1173 | + $magic = MimeMagic::singleton(); |
| 1174 | + $mime = $magic->guessMimeType( $tempFile, true ); |
| 1175 | + $media_type = $magic->getMediaType( $tempFile, $mime ); |
| 1176 | + list( $major_mime, $minor_mime ) = self::splitMime( $mime ); |
| 1177 | + $handler = MediaHandler::getHandler( $mime ); |
| 1178 | + if ( $handler ) { |
| 1179 | + $metadata = $handler->getMetadata( false, $tempFile ); |
| 1180 | + } else { |
| 1181 | + $metadata = ''; |
| 1182 | + } |
| 1183 | + } else { |
| 1184 | + $metadata = $row->fa_metadata; |
| 1185 | + $major_mime = $row->fa_major_mime; |
| 1186 | + $minor_mime = $row->fa_minor_mime; |
| 1187 | + $media_type = $row->fa_media_type; |
| 1188 | + } |
| 1189 | + |
| 1190 | + $table = 'image'; |
| 1191 | + $fields = array( |
| 1192 | + 'img_name' => $row->fa_name, |
| 1193 | + 'img_size' => $row->fa_size, |
| 1194 | + 'img_width' => $row->fa_width, |
| 1195 | + 'img_height' => $row->fa_height, |
| 1196 | + 'img_metadata' => $metadata, |
| 1197 | + 'img_bits' => $row->fa_bits, |
| 1198 | + 'img_media_type' => $media_type, |
| 1199 | + 'img_major_mime' => $major_mime, |
| 1200 | + 'img_minor_mime' => $minor_mime, |
| 1201 | + 'img_description' => $row->fa_description, |
| 1202 | + 'img_user' => $row->fa_user, |
| 1203 | + 'img_user_text' => $row->fa_user_text, |
| 1204 | + 'img_timestamp' => $row->fa_timestamp ); |
| 1205 | + } else { |
| 1206 | + $archiveName = $row->fa_archive_name; |
| 1207 | + if( $archiveName == '' ) { |
| 1208 | + // This was originally a current version; we |
| 1209 | + // have to devise a new archive name for it. |
| 1210 | + // Format is <timestamp of archiving>!<name> |
| 1211 | + $archiveName = |
| 1212 | + wfTimestamp( TS_MW, $row->fa_deleted_timestamp ) . |
| 1213 | + '!' . $row->fa_name; |
| 1214 | + } |
| 1215 | + $restoredImage = new self( $row->fa_name, $this->repo ); |
| 1216 | + $destDir = $restoredImage->getArchivePath(); |
| 1217 | + if ( !is_dir( $destDir ) ) { |
| 1218 | + wfMkdirParents( $destDir ); |
| 1219 | + } |
| 1220 | + $destPath = $destDir . DIRECTORY_SEPARATOR . $archiveName; |
| 1221 | + |
| 1222 | + $table = 'oldimage'; |
| 1223 | + $fields = array( |
| 1224 | + 'oi_name' => $row->fa_name, |
| 1225 | + 'oi_archive_name' => $archiveName, |
| 1226 | + 'oi_size' => $row->fa_size, |
| 1227 | + 'oi_width' => $row->fa_width, |
| 1228 | + 'oi_height' => $row->fa_height, |
| 1229 | + 'oi_bits' => $row->fa_bits, |
| 1230 | + 'oi_description' => $row->fa_description, |
| 1231 | + 'oi_user' => $row->fa_user, |
| 1232 | + 'oi_user_text' => $row->fa_user_text, |
| 1233 | + 'oi_timestamp' => $row->fa_timestamp ); |
| 1234 | + } |
| 1235 | + |
| 1236 | + $dbw->insert( $table, $fields, __METHOD__ ); |
| 1237 | + // @todo this delete is not totally safe, potentially |
| 1238 | + $dbw->delete( 'filearchive', |
| 1239 | + array( 'fa_id' => $row->fa_id ), |
| 1240 | + __METHOD__ ); |
| 1241 | + |
| 1242 | + // Check if any other stored revisions use this file; |
| 1243 | + // if so, we shouldn't remove the file from the deletion |
| 1244 | + // archives so they will still work. |
| 1245 | + $useCount = $dbw->selectField( 'filearchive', |
| 1246 | + 'COUNT(*)', |
| 1247 | + array( |
| 1248 | + 'fa_storage_group' => $row->fa_storage_group, |
| 1249 | + 'fa_storage_key' => $row->fa_storage_key ), |
| 1250 | + __METHOD__ ); |
| 1251 | + if( $useCount == 0 ) { |
| 1252 | + wfDebug( __METHOD__.": nothing else using {$row->fa_storage_key}, will deleting after\n" ); |
| 1253 | + $flags = FileStore::DELETE_ORIGINAL; |
| 1254 | + } else { |
| 1255 | + $flags = 0; |
| 1256 | + } |
| 1257 | + |
| 1258 | + $transaction->add( $store->export( $row->fa_storage_key, |
| 1259 | + $destPath, $flags ) ); |
| 1260 | + } |
| 1261 | + |
| 1262 | + $dbw->immediateCommit(); |
| 1263 | + } catch( MWException $e ) { |
| 1264 | + wfDebug( __METHOD__." caught error, aborting\n" ); |
| 1265 | + $transaction->rollback(); |
| 1266 | + throw $e; |
| 1267 | + } |
| 1268 | + |
| 1269 | + $transaction->commit(); |
| 1270 | + FileStore::unlock(); |
| 1271 | + |
| 1272 | + if( $revisions > 0 ) { |
| 1273 | + if( !$exists ) { |
| 1274 | + wfDebug( __METHOD__." restored $revisions items, creating a new current\n" ); |
| 1275 | + |
| 1276 | + // Update site_stats |
| 1277 | + $site_stats = $dbw->tableName( 'site_stats' ); |
| 1278 | + $dbw->query( "UPDATE $site_stats SET ss_images=ss_images+1", __METHOD__ ); |
| 1279 | + |
| 1280 | + $this->purgeEverything(); |
| 1281 | + } else { |
| 1282 | + wfDebug( __METHOD__." restored $revisions as archived versions\n" ); |
| 1283 | + $this->purgeDescription(); |
| 1284 | + } |
| 1285 | + } |
| 1286 | + |
| 1287 | + return $revisions; |
| 1288 | + } |
| 1289 | + |
| 1290 | + /** isMultipage inherited */ |
| 1291 | + /** pageCount inherited */ |
| 1292 | + /** scaleHeight inherited */ |
| 1293 | + /** getImageSize inherited */ |
| 1294 | + |
| 1295 | + /** |
| 1296 | + * Get the URL of the file description page. |
| 1297 | + */ |
| 1298 | + function getDescriptionUrl() { |
| 1299 | + return $this->title->getLocalUrl(); |
| 1300 | + } |
| 1301 | + |
| 1302 | + /** |
| 1303 | + * Get the HTML text of the description page |
| 1304 | + * This is not used by ImagePage for local files, since (among other things) |
| 1305 | + * it skips the parser cache. |
| 1306 | + */ |
| 1307 | + function getDescriptionText() { |
| 1308 | + global $wgParser; |
| 1309 | + $revision = Revision::newFromTitle( $this->title ); |
| 1310 | + if ( !$revision ) return false; |
| 1311 | + $text = $revision->getText(); |
| 1312 | + if ( !$text ) return false; |
| 1313 | + $html = $wgParser->parse( $text, new ParserOptions ); |
| 1314 | + return $html; |
| 1315 | + } |
| 1316 | + |
| 1317 | + function getTimestamp() { |
| 1318 | + $this->load(); |
| 1319 | + return $this->timestamp; |
| 1320 | + } |
| 1321 | +} // LocalFile class |
| 1322 | + |
| 1323 | +/** |
| 1324 | + * Backwards compatibility class |
| 1325 | + */ |
| 1326 | +class Image extends LocalFile { |
| 1327 | + function __construct( $title ) { |
| 1328 | + $repo = FileRepoGroup::singleton()->getLocalRepo(); |
| 1329 | + parent::__construct( $title, $repo ); |
| 1330 | + } |
| 1331 | + |
| 1332 | + /** |
| 1333 | + * Wrapper for wfFindFile(), for backwards-compatibility only |
| 1334 | + * Do not use in core code. |
| 1335 | + */ |
| 1336 | + function newFromTitle( $title, $time = false ) { |
| 1337 | + $img = wfFindFile( $title, $time ); |
| 1338 | + if ( !$img ) { |
| 1339 | + $img = wfLocalFile( $title ); |
| 1340 | + } |
| 1341 | + return $img; |
| 1342 | + } |
| 1343 | +} |
| 1344 | + |
| 1345 | +/** |
| 1346 | + * Aliases for backwards compatibility with 1.6 |
| 1347 | + */ |
| 1348 | +define( 'MW_IMG_DELETED_FILE', File::DELETED_FILE ); |
| 1349 | +define( 'MW_IMG_DELETED_COMMENT', File::DELETED_COMMENT ); |
| 1350 | +define( 'MW_IMG_DELETED_USER', File::DELETED_USER ); |
| 1351 | +define( 'MW_IMG_DELETED_RESTRICTED', File::DELETED_RESTRICTED ); |
| 1352 | + |
| 1353 | +?> |
Property changes on: branches/liquidthreads/includes/filerepo/LocalFile.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 1354 | + native |
Index: branches/liquidthreads/includes/filerepo/UnregisteredLocalFile.php |
— | — | @@ -0,0 +1,109 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * A file object referring to either a standalone local file, or a file in a |
| 6 | + * local repository with no database, for example an FSRepo repository. |
| 7 | + * |
| 8 | + * Read-only. |
| 9 | + * |
| 10 | + * TODO: Currently it doesn't really work in the repository role, there are |
| 11 | + * lots of functions missing. It is used by the WebStore extension in the |
| 12 | + * standalone role. |
| 13 | + */ |
| 14 | +class UnregisteredLocalFile extends File { |
| 15 | + var $title, $path, $mime, $handler, $dims; |
| 16 | + |
| 17 | + function newFromPath( $path, $mime ) { |
| 18 | + return new UnregisteredLocalFile( false, false, $path, $mime ); |
| 19 | + } |
| 20 | + |
| 21 | + function newFromTitle( $title, $repo ) { |
| 22 | + return new UnregisteredLocalFile( $title, $repo, false, false ); |
| 23 | + } |
| 24 | + |
| 25 | + function __construct( $title = false, $repo = false, $path = false, $mime = false ) { |
| 26 | + if ( !( $title && $repo ) && !$path ) { |
| 27 | + throw new MWException( __METHOD__.': not enough parameters, must specify title and repo, or a full path' ); |
| 28 | + } |
| 29 | + if ( $title ) { |
| 30 | + $this->title = $title; |
| 31 | + $this->name = $title->getDBkey(); |
| 32 | + } else { |
| 33 | + $this->name = basename( $path ); |
| 34 | + $this->title = Title::makeTitleSafe( NS_IMAGE, $this->name ); |
| 35 | + } |
| 36 | + $this->repo = $repo; |
| 37 | + if ( $path ) { |
| 38 | + $this->path = $path; |
| 39 | + } else { |
| 40 | + $this->path = $repo->getRootDirectory() . '/' . $repo->getHashPath( $this->name ) . $this->name; |
| 41 | + } |
| 42 | + if ( $mime ) { |
| 43 | + $this->mime = $mime; |
| 44 | + } |
| 45 | + $this->dims = array(); |
| 46 | + } |
| 47 | + |
| 48 | + function getPageDimensions( $page = 1 ) { |
| 49 | + if ( !isset( $this->dims[$page] ) ) { |
| 50 | + if ( !$this->getHandler() ) { |
| 51 | + return false; |
| 52 | + } |
| 53 | + $this->dims[$page] = $this->handler->getPageDimensions( $this, $page ); |
| 54 | + } |
| 55 | + return $this->dims[$page]; |
| 56 | + } |
| 57 | + |
| 58 | + function getWidth( $page = 1 ) { |
| 59 | + $dim = $this->getPageDimensions( $page ); |
| 60 | + return $dim['width']; |
| 61 | + } |
| 62 | + |
| 63 | + function getHeight( $page = 1 ) { |
| 64 | + $dim = $this->getPageDimensions( $page ); |
| 65 | + return $dim['height']; |
| 66 | + } |
| 67 | + |
| 68 | + function getMimeType() { |
| 69 | + if ( !isset( $this->mime ) ) { |
| 70 | + $magic = MimeMagic::singleton(); |
| 71 | + $this->mime = $magic->guessMimeType( $this->path ); |
| 72 | + } |
| 73 | + return $this->mime; |
| 74 | + } |
| 75 | + |
| 76 | + function getImageSize() { |
| 77 | + if ( !$this->getHandler() ) { |
| 78 | + return false; |
| 79 | + } |
| 80 | + return $this->handler->getImageSize( $this, $this->getPath() ); |
| 81 | + } |
| 82 | + |
| 83 | + function getMetadata() { |
| 84 | + if ( !isset( $this->metadata ) ) { |
| 85 | + if ( !$this->getHandler() ) { |
| 86 | + $this->metadata = false; |
| 87 | + } else { |
| 88 | + $this->metadata = $this->handler->getMetadata( $this, $this->getPath() ); |
| 89 | + } |
| 90 | + } |
| 91 | + return $this->metadata; |
| 92 | + } |
| 93 | + |
| 94 | + function getURL() { |
| 95 | + if ( $this->repo ) { |
| 96 | + return $this->repo->getZoneUrl( 'public' ) . $this->repo->getHashPath( $this->name ) . urlencode( $this->name ); |
| 97 | + } else { |
| 98 | + return false; |
| 99 | + } |
| 100 | + } |
| 101 | + |
| 102 | + function getSize() { |
| 103 | + if ( file_exists( $this->path ) ) { |
| 104 | + return filesize( $this->path ); |
| 105 | + } else { |
| 106 | + return false; |
| 107 | + } |
| 108 | + } |
| 109 | +} |
| 110 | +?> |
Property changes on: branches/liquidthreads/includes/filerepo/UnregisteredLocalFile.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 111 | + native |
Index: branches/liquidthreads/includes/ImagePage.php |
— | — | @@ -18,6 +18,14 @@ |
19 | 19 | /* private */ var $img; // Image object this page is shown for |
20 | 20 | var $mExtraDescription = false; |
21 | 21 | |
| 22 | + function __construct( $title ) { |
| 23 | + parent::__construct( $title ); |
| 24 | + $this->img = wfFindFile( $this->mTitle ); |
| 25 | + if ( !$this->img ) { |
| 26 | + $this->img = wfLocalFile( $this->mTitle ); |
| 27 | + } |
| 28 | + } |
| 29 | + |
22 | 30 | /** |
23 | 31 | * Handler for action=render |
24 | 32 | * Include body text only; none of the image extras |
— | — | @@ -31,8 +39,6 @@ |
32 | 40 | function view() { |
33 | 41 | global $wgOut, $wgShowEXIF, $wgRequest, $wgUser; |
34 | 42 | |
35 | | - $this->img = new Image( $this->mTitle ); |
36 | | - |
37 | 43 | $diff = $wgRequest->getVal( 'diff' ); |
38 | 44 | $diffOnly = $wgRequest->getBool( 'diffonly', $wgUser->getOption( 'diffonly' ) ); |
39 | 45 | |
— | — | @@ -160,7 +166,7 @@ |
161 | 167 | * shared upload server if possible. |
162 | 168 | */ |
163 | 169 | function getContent() { |
164 | | - if( $this->img && $this->img->fromSharedDirectory && 0 == $this->getID() ) { |
| 170 | + if( $this->img && !$this->img->isLocal() && 0 == $this->getID() ) { |
165 | 171 | return ''; |
166 | 172 | } |
167 | 173 | return Article::getContent(); |
— | — | @@ -332,26 +338,26 @@ |
333 | 339 | $dirmark = $wgContLang->getDirMark(); |
334 | 340 | if (!$this->img->isSafeFile()) { |
335 | 341 | $warning = wfMsg( 'mediawarning' ); |
336 | | - $wgOut->addWikiText( <<<END |
| 342 | + $wgOut->addWikiText( <<<EOT |
337 | 343 | <div class="fullMedia">$infores |
338 | 344 | <span class="dangerousLink">[[Media:$filename|$filename]]</span>$dirmark |
339 | 345 | <span class="fileInfo"> $info</span> |
340 | 346 | </div> |
341 | 347 | |
342 | 348 | <div class="mediaWarning">$warning</div> |
343 | | -END |
| 349 | +EOT |
344 | 350 | ); |
345 | 351 | } else { |
346 | | - $wgOut->addWikiText( <<<END |
| 352 | + $wgOut->addWikiText( <<<EOT |
347 | 353 | <div class="fullMedia">$infores |
348 | 354 | [[Media:$filename|$filename]]$dirmark <span class="fileInfo"> $info</span> |
349 | 355 | </div> |
350 | | -END |
| 356 | +EOT |
351 | 357 | ); |
352 | 358 | } |
353 | 359 | } |
354 | 360 | |
355 | | - if($this->img->fromSharedDirectory) { |
| 361 | + if(!$this->img->isLocal()) { |
356 | 362 | $this->printSharedImageText(); |
357 | 363 | } |
358 | 364 | } else { |
— | — | @@ -365,27 +371,21 @@ |
366 | 372 | } |
367 | 373 | |
368 | 374 | function printSharedImageText() { |
369 | | - global $wgRepositoryBaseUrl, $wgFetchCommonsDescriptions, $wgOut, $wgUser; |
| 375 | + global $wgOut, $wgUser; |
370 | 376 | |
371 | | - $url = $wgRepositoryBaseUrl . urlencode($this->mTitle->getDBkey()); |
372 | | - $sharedtext = "<div class='sharedUploadNotice'>" . wfMsgWikiHtml("sharedupload"); |
373 | | - if ($wgRepositoryBaseUrl && !$wgFetchCommonsDescriptions) { |
374 | | - |
| 377 | + $descUrl = $this->img->getDescriptionUrl(); |
| 378 | + $descText = $this->img->getDescriptionText(); |
| 379 | + $s = "<div class='sharedUploadNotice'>" . wfMsgWikiHtml("sharedupload"); |
| 380 | + if ( $descUrl && !$descText) { |
375 | 381 | $sk = $wgUser->getSkin(); |
376 | | - $title = SpecialPage::getTitleFor( 'Upload' ); |
377 | | - $link = $sk->makeKnownLinkObj($title, wfMsgHtml('shareduploadwiki-linktext'), |
378 | | - array( 'wpDestFile' => urlencode( $this->img->getName() ))); |
379 | | - $sharedtext .= " " . wfMsgWikiHtml('shareduploadwiki', $link); |
| 382 | + $link = $sk->makeExternalLink( $descUrl, wfMsg('shareduploadwiki-linktext') ); |
| 383 | + $s .= " " . wfMsgWikiHtml('shareduploadwiki', $link); |
380 | 384 | } |
381 | | - $sharedtext .= "</div>"; |
382 | | - $wgOut->addHTML($sharedtext); |
| 385 | + $s .= "</div>"; |
| 386 | + $wgOut->addHTML($s); |
383 | 387 | |
384 | | - if ($wgRepositoryBaseUrl && $wgFetchCommonsDescriptions) { |
385 | | - $renderUrl = wfAppendQuery( $url, 'action=render' ); |
386 | | - wfDebug( "Fetching shared description from $renderUrl\n" ); |
387 | | - $text = Http::get( $renderUrl ); |
388 | | - if ($text) |
389 | | - $this->mExtraDescription = $text; |
| 388 | + if ( $descText ) { |
| 389 | + $this->mExtraDescription = $descText; |
390 | 390 | } |
391 | 391 | } |
392 | 392 | |
— | — | @@ -402,7 +402,7 @@ |
403 | 403 | function uploadLinksBox() { |
404 | 404 | global $wgUser, $wgOut; |
405 | 405 | |
406 | | - if( $this->img->fromSharedDirectory ) |
| 406 | + if( !$this->img->isLocal() ) |
407 | 407 | return; |
408 | 408 | |
409 | 409 | $sk = $wgUser->getSkin(); |
— | — | @@ -441,7 +441,7 @@ |
442 | 442 | $line = $this->img->nextHistoryLine(); |
443 | 443 | |
444 | 444 | if ( $line ) { |
445 | | - $list = new ImageHistoryList( $sk ); |
| 445 | + $list = new ImageHistoryList( $sk, $this->img ); |
446 | 446 | $s = $list->beginImageHistoryList() . |
447 | 447 | $list->imageHistoryLine( true, wfTimestamp(TS_MW, $line->img_timestamp), |
448 | 448 | $this->mTitle->getDBkey(), $line->img_user, |
— | — | @@ -530,8 +530,6 @@ |
531 | 531 | return; |
532 | 532 | } |
533 | 533 | |
534 | | - $this->img = new Image( $this->mTitle ); |
535 | | - |
536 | 534 | # Deleting old images doesn't require confirmation |
537 | 535 | if ( !is_null( $oldimage ) || $confirm ) { |
538 | 536 | if( $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ), $oldimage ) ) { |
— | — | @@ -655,39 +653,23 @@ |
656 | 654 | $wgOut->showErrorPage( 'internalerror', 'sessionfailure' ); |
657 | 655 | return; |
658 | 656 | } |
659 | | - $name = substr( $oldimage, 15 ); |
660 | 657 | |
661 | | - $dest = wfImageDir( $name ); |
662 | | - $archive = wfImageArchiveDir( $name ); |
663 | | - $curfile = "{$dest}/{$name}"; |
| 658 | + $sourcePath = $this->img->getArchiveVirtualUrl( $oldimage ); |
| 659 | + $result = $this->img->publish( $sourcePath ); |
664 | 660 | |
665 | | - if ( !is_dir( $dest ) ) wfMkdirParents( $dest ); |
666 | | - if ( !is_dir( $archive ) ) wfMkdirParents( $archive ); |
667 | | - |
668 | | - if ( ! is_file( $curfile ) ) { |
669 | | - $wgOut->showFileNotFoundError( htmlspecialchars( $curfile ) ); |
| 661 | + if ( WikiError::isError( $result ) ) { |
| 662 | + $this->showError( $result ); |
670 | 663 | return; |
671 | 664 | } |
672 | | - $oldver = wfTimestampNow() . "!{$name}"; |
673 | 665 | |
674 | | - if ( ! rename( $curfile, "${archive}/{$oldver}" ) ) { |
675 | | - $wgOut->showFileRenameError( $curfile, "${archive}/{$oldver}" ); |
676 | | - return; |
677 | | - } |
678 | | - if ( ! copy( "{$archive}/{$oldimage}", $curfile ) ) { |
679 | | - $wgOut->showFileCopyError( "${archive}/{$oldimage}", $curfile ); |
680 | | - return; |
681 | | - } |
682 | | - |
683 | 666 | # Record upload and update metadata cache |
684 | | - $img = Image::newFromName( $name ); |
685 | | - $img->recordUpload( $oldver, wfMsg( "reverted" ) ); |
| 667 | + $this->img->recordUpload( $result, wfMsg( "reverted" ) ); |
686 | 668 | |
687 | 669 | $wgOut->setPagetitle( wfMsg( 'actioncomplete' ) ); |
688 | 670 | $wgOut->setRobotpolicy( 'noindex,nofollow' ); |
689 | 671 | $wgOut->addHTML( wfMsg( 'imagereverted' ) ); |
690 | 672 | |
691 | | - $descTitle = $img->getTitle(); |
| 673 | + $descTitle = $this->img->getTitle(); |
692 | 674 | $wgOut->returnToMain( false, $descTitle->getPrefixedText() ); |
693 | 675 | } |
694 | 676 | |
— | — | @@ -695,7 +677,6 @@ |
696 | 678 | * Override handling of action=purge |
697 | 679 | */ |
698 | 680 | function doPurge() { |
699 | | - $this->img = new Image( $this->mTitle ); |
700 | 681 | if( $this->img->exists() ) { |
701 | 682 | wfDebug( "ImagePage::doPurge purging " . $this->img->getName() . "\n" ); |
702 | 683 | $update = new HTMLCacheUpdate( $this->mTitle, 'imagelinks' ); |
— | — | @@ -708,6 +689,18 @@ |
709 | 690 | parent::doPurge(); |
710 | 691 | } |
711 | 692 | |
| 693 | + /** |
| 694 | + * Display an error from a wikitext-formatted WikiError object |
| 695 | + */ |
| 696 | + function showError( WikiError $error ) { |
| 697 | + global $wgOut; |
| 698 | + $wgOut->setPageTitle( wfMsg( "internalerror" ) ); |
| 699 | + $wgOut->setRobotpolicy( "noindex,nofollow" ); |
| 700 | + $wgOut->setArticleRelated( false ); |
| 701 | + $wgOut->enableClientCache( false ); |
| 702 | + $wgOut->addWikiText( $error->getMessage() ); |
| 703 | + } |
| 704 | + |
712 | 705 | } |
713 | 706 | |
714 | 707 | /** |
— | — | @@ -715,8 +708,10 @@ |
716 | 709 | * @addtogroup Media |
717 | 710 | */ |
718 | 711 | class ImageHistoryList { |
719 | | - function ImageHistoryList( &$skin ) { |
720 | | - $this->skin =& $skin; |
| 712 | + var $img, $skin; |
| 713 | + function ImageHistoryList( $skin, $img ) { |
| 714 | + $this->skin = $skin; |
| 715 | + $this->img = $img; |
721 | 716 | } |
722 | 717 | |
723 | 718 | function beginImageHistoryList() { |
— | — | @@ -738,11 +733,12 @@ |
739 | 734 | $del = wfMsgHtml( 'deleteimg' ); |
740 | 735 | $delall = wfMsgHtml( 'deleteimgcompletely' ); |
741 | 736 | $cur = wfMsgHtml( 'cur' ); |
| 737 | + $local = $this->img->isLocal(); |
742 | 738 | |
743 | 739 | if ( $iscur ) { |
744 | | - $url = Image::imageUrl( $img ); |
| 740 | + $url = htmlspecialchars( $this->img->getURL() ); |
745 | 741 | $rlink = $cur; |
746 | | - if ( $wgUser->isAllowed('delete') ) { |
| 742 | + if ( $local && $wgUser->isAllowed('delete') ) { |
747 | 743 | $link = $wgTitle->escapeLocalURL( 'image=' . $wgTitle->getPartialURL() . |
748 | 744 | '&action=delete' ); |
749 | 745 | $style = $this->skin->getInternalLinkAttributes( $link, $delall ); |
— | — | @@ -752,8 +748,8 @@ |
753 | 749 | $dlink = $del; |
754 | 750 | } |
755 | 751 | } else { |
756 | | - $url = htmlspecialchars( wfImageArchiveUrl( $img ) ); |
757 | | - if( $wgUser->getID() != 0 && $wgTitle->userCan( 'edit' ) ) { |
| 752 | + $url = htmlspecialchars( $this->img->getArchiveUrl( $img ) ); |
| 753 | + if( $local && $wgUser->getID() != 0 && $wgTitle->userCan( 'edit' ) ) { |
758 | 754 | $token = urlencode( $wgUser->editToken( $img ) ); |
759 | 755 | $rlink = $this->skin->makeKnownLinkObj( $wgTitle, |
760 | 756 | wfMsgHtml( 'revertimg' ), 'action=revert&oldimage=' . |
— | — | @@ -769,8 +765,12 @@ |
770 | 766 | $dlink = $del; |
771 | 767 | } |
772 | 768 | } |
773 | | - |
774 | | - $userlink = $this->skin->userLink( $user, $usertext ) . $this->skin->userToolLinks( $user, $usertext ); |
| 769 | + |
| 770 | + if ( $local ) { |
| 771 | + $userlink = $this->skin->userLink( $user, $usertext ) . $this->skin->userToolLinks( $user, $usertext ); |
| 772 | + } else { |
| 773 | + $userlink = htmlspecialchars( $usertext ); |
| 774 | + } |
775 | 775 | $nbytes = wfMsgExt( 'nbytes', array( 'parsemag', 'escape' ), |
776 | 776 | $wgLang->formatNum( $size ) ); |
777 | 777 | $widthheight = wfMsgHtml( 'widthheight', $width, $height ); |
— | — | @@ -782,7 +782,6 @@ |
783 | 783 | $s .= "</li>\n"; |
784 | 784 | return $s; |
785 | 785 | } |
786 | | - |
787 | 786 | } |
788 | 787 | |
789 | 788 | |
Index: branches/liquidthreads/includes/StreamFile.php |
— | — | @@ -31,6 +31,9 @@ |
32 | 32 | header('Content-type: application/x-wiki'); |
33 | 33 | } |
34 | 34 | |
| 35 | + global $wgContLanguageCode; |
| 36 | + header( "Content-Disposition: inline;filename*=utf-8'$wgContLanguageCode'" . urlencode( basename( $fname ) ) ); |
| 37 | + |
35 | 38 | if ( !empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ) { |
36 | 39 | $modsince = preg_replace( '/;.*$/', '', $_SERVER['HTTP_IF_MODIFIED_SINCE'] ); |
37 | 40 | $sinceTime = strtotime( $modsince ); |
Index: branches/liquidthreads/includes/SpecialUndelete.php |
— | — | @@ -269,7 +269,7 @@ |
270 | 270 | $restoreFiles = $restoreAll || !empty( $fileVersions ); |
271 | 271 | |
272 | 272 | if( $restoreFiles && $this->title->getNamespace() == NS_IMAGE ) { |
273 | | - $img = new Image( $this->title ); |
| 273 | + $img = wfLocalFile( $this->title ); |
274 | 274 | $filesRestored = $img->restore( $fileVersions ); |
275 | 275 | } else { |
276 | 276 | $filesRestored = 0; |
Index: branches/liquidthreads/includes/Linker.php |
— | — | @@ -440,13 +440,14 @@ |
441 | 441 | * @return string |
442 | 442 | */ |
443 | 443 | function makeImageLinkObj( $nt, $label, $alt, $align = '', $params = array(), $framed = false, |
444 | | - $thumb = false, $manual_thumb = '', $valign = '' ) |
| 444 | + $thumb = false, $manual_thumb = '', $valign = '', $time = false ) |
445 | 445 | { |
446 | 446 | global $wgContLang, $wgUser, $wgThumbLimits, $wgThumbUpright; |
447 | 447 | |
448 | | - $img = new Image( $nt ); |
| 448 | + $img = wfFindFile( $nt, $time ); |
449 | 449 | |
450 | | - if ( !$img->allowInlineDisplay() && $img->exists() ) { |
| 450 | + if ( $img && !$img->allowInlineDisplay() ) { |
| 451 | + wfDebug( __METHOD__.': '.$nt->getPrefixedDBkey()." does not allow inline display\n" ); |
451 | 452 | return $this->makeKnownLinkObj( $nt ); |
452 | 453 | } |
453 | 454 | |
— | — | @@ -459,7 +460,7 @@ |
460 | 461 | $postfix = '</div>'; |
461 | 462 | $align = 'none'; |
462 | 463 | } |
463 | | - if ( !isset( $params['width'] ) ) { |
| 464 | + if ( $img && !isset( $params['width'] ) ) { |
464 | 465 | $params['width'] = $img->getWidth( $page ); |
465 | 466 | if( $thumb || $framed || isset( $params['frameless'] ) ) { |
466 | 467 | $wopt = $wgUser->getOption( 'thumbsize' ); |
— | — | @@ -490,10 +491,10 @@ |
491 | 492 | if ( $align == '' ) { |
492 | 493 | $align = $wgContLang->isRTL() ? 'left' : 'right'; |
493 | 494 | } |
494 | | - return $prefix.$this->makeThumbLinkObj( $img, $label, $alt, $align, $params, $framed, $manual_thumb ).$postfix; |
| 495 | + return $prefix.$this->makeThumbLinkObj( $nt, $img, $label, $alt, $align, $params, $framed, $manual_thumb ).$postfix; |
495 | 496 | } |
496 | 497 | |
497 | | - if ( $params['width'] && $img->exists() ) { |
| 498 | + if ( $img && $params['width'] ) { |
498 | 499 | # Create a resized image, without the additional thumbnail features |
499 | 500 | $thumb = $img->transform( $params ); |
500 | 501 | } else { |
— | — | @@ -524,7 +525,7 @@ |
525 | 526 | ); |
526 | 527 | |
527 | 528 | if ( !$thumb ) { |
528 | | - $s = $this->makeBrokenImageLinkObj( $img->getTitle() ); |
| 529 | + $s = $this->makeBrokenImageLinkObj( $nt ); |
529 | 530 | } else { |
530 | 531 | $s = $thumb->toHtml( $imgAttribs, $linkAttribs ); |
531 | 532 | } |
— | — | @@ -536,10 +537,12 @@ |
537 | 538 | |
538 | 539 | /** |
539 | 540 | * Make HTML for a thumbnail including image, border and caption |
540 | | - * $img is an Image object |
| 541 | + * @param Title $nt |
| 542 | + * @param Image $img Image object or false if it doesn't exist |
541 | 543 | */ |
542 | | - function makeThumbLinkObj( $img, $label = '', $alt, $align = 'right', $params = array(), $framed=false , $manual_thumb = "" ) { |
| 544 | + function makeThumbLinkObj( Title $nt, $img, $label = '', $alt, $align = 'right', $params = array(), $framed=false , $manual_thumb = "" ) { |
543 | 545 | global $wgStylePath, $wgContLang; |
| 546 | + $exists = $img && $img->exists(); |
544 | 547 | |
545 | 548 | $page = isset( $params['page'] ) ? $params['page'] : false; |
546 | 549 | |
— | — | @@ -548,46 +551,55 @@ |
549 | 552 | $params['width'] = isset( $params['upright'] ) ? 130 : 180; |
550 | 553 | } |
551 | 554 | $thumb = false; |
552 | | - if ( $manual_thumb != '' ) { |
553 | | - # Use manually specified thumbnail |
554 | | - $manual_title = Title::makeTitleSafe( NS_IMAGE, $manual_thumb ); |
555 | | - if( $manual_title ) { |
556 | | - $manual_img = new Image( $manual_title ); |
557 | | - $thumb = $manual_img->getUnscaledThumb(); |
558 | | - } |
559 | | - } elseif ( $framed ) { |
560 | | - // Use image dimensions, don't scale |
561 | | - $thumb = $img->getUnscaledThumb( $page ); |
| 555 | + |
| 556 | + if ( !$exists ) { |
| 557 | + $outerWidth = $params['width'] + 2; |
562 | 558 | } else { |
563 | | - # Do not present an image bigger than the source, for bitmap-style images |
564 | | - # This is a hack to maintain compatibility with arbitrary pre-1.10 behaviour |
565 | | - $srcWidth = $img->getWidth( $page ); |
566 | | - if ( $srcWidth && !$img->mustRender() && $params['width'] > $srcWidth ) { |
567 | | - $params['width'] = $srcWidth; |
| 559 | + if ( $manual_thumb != '' ) { |
| 560 | + # Use manually specified thumbnail |
| 561 | + $manual_title = Title::makeTitleSafe( NS_IMAGE, $manual_thumb ); |
| 562 | + if( $manual_title ) { |
| 563 | + $manual_img = wfFindFile( $manual_title ); |
| 564 | + if ( $manual_img ) { |
| 565 | + $thumb = $manual_img->getUnscaledThumb(); |
| 566 | + } else { |
| 567 | + $exists = false; |
| 568 | + } |
| 569 | + } |
| 570 | + } elseif ( $framed ) { |
| 571 | + // Use image dimensions, don't scale |
| 572 | + $thumb = $img->getUnscaledThumb( $page ); |
| 573 | + } else { |
| 574 | + # Do not present an image bigger than the source, for bitmap-style images |
| 575 | + # This is a hack to maintain compatibility with arbitrary pre-1.10 behaviour |
| 576 | + $srcWidth = $img->getWidth( $page ); |
| 577 | + if ( $srcWidth && !$img->mustRender() && $params['width'] > $srcWidth ) { |
| 578 | + $params['width'] = $srcWidth; |
| 579 | + } |
| 580 | + $thumb = $img->transform( $params ); |
568 | 581 | } |
569 | | - $thumb = $img->transform( $params ); |
570 | | - } |
571 | 582 | |
572 | | - if ( $thumb ) { |
573 | | - $outerWidth = $thumb->getWidth() + 2; |
574 | | - } else { |
575 | | - $outerWidth = $params['width'] + 2; |
| 583 | + if ( $thumb ) { |
| 584 | + $outerWidth = $thumb->getWidth() + 2; |
| 585 | + } else { |
| 586 | + $outerWidth = $params['width'] + 2; |
| 587 | + } |
576 | 588 | } |
577 | 589 | |
578 | 590 | $query = $page ? 'page=' . urlencode( $page ) : ''; |
579 | | - $u = $img->getTitle()->getLocalURL( $query ); |
| 591 | + $u = $nt->getLocalURL( $query ); |
580 | 592 | |
581 | 593 | $more = htmlspecialchars( wfMsg( 'thumbnail-more' ) ); |
582 | 594 | $magnifyalign = $wgContLang->isRTL() ? 'left' : 'right'; |
583 | 595 | $textalign = $wgContLang->isRTL() ? ' style="text-align:right"' : ''; |
584 | 596 | |
585 | 597 | $s = "<div class=\"thumb t{$align}\"><div class=\"thumbinner\" style=\"width:{$outerWidth}px;\">"; |
586 | | - if ( !$thumb ) { |
| 598 | + if( !$exists ) { |
| 599 | + $s .= $this->makeBrokenImageLinkObj( $nt ); |
| 600 | + $zoomicon = ''; |
| 601 | + } elseif ( !$thumb ) { |
587 | 602 | $s .= htmlspecialchars( wfMsg( 'thumbnail_error', '' ) ); |
588 | 603 | $zoomicon = ''; |
589 | | - } elseif( !$img->exists() ) { |
590 | | - $s .= $this->makeBrokenImageLinkObj( $img->getTitle() ); |
591 | | - $zoomicon = ''; |
592 | 604 | } else { |
593 | 605 | $imgAttribs = array( |
594 | 606 | 'alt' => $alt, |
— | — | @@ -645,10 +657,10 @@ |
646 | 658 | return $s; |
647 | 659 | } |
648 | 660 | |
649 | | - /** @todo document */ |
650 | | - function makeMediaLink( $name, /* wtf?! */ $url, $alt = '' ) { |
| 661 | + /** @deprecated use Linker::makeMediaLinkObj() */ |
| 662 | + function makeMediaLink( $name, $unused = '', $text = '' ) { |
651 | 663 | $nt = Title::makeTitleSafe( NS_IMAGE, $name ); |
652 | | - return $this->makeMediaLinkObj( $nt, $alt ); |
| 664 | + return $this->makeMediaLinkObj( $nt, $text ); |
653 | 665 | } |
654 | 666 | |
655 | 667 | /** |
— | — | @@ -666,13 +678,13 @@ |
667 | 679 | ### HOTFIX. Instead of breaking, return empty string. |
668 | 680 | return $text; |
669 | 681 | } else { |
670 | | - $img = new Image( $title ); |
671 | | - if( $img->exists() ) { |
| 682 | + $img = wfFindFile( $title ); |
| 683 | + if( $img ) { |
672 | 684 | $url = $img->getURL(); |
673 | 685 | $class = 'internal'; |
674 | 686 | } else { |
675 | 687 | $upload = SpecialPage::getTitleFor( 'Upload' ); |
676 | | - $url = $upload->getLocalUrl( 'wpDestFile=' . urlencode( $img->getName() ) ); |
| 688 | + $url = $upload->getLocalUrl( 'wpDestFile=' . urlencode( $title->getText() ) ); |
677 | 689 | $class = 'new'; |
678 | 690 | } |
679 | 691 | $alt = htmlspecialchars( $title->getText() ); |
Index: branches/liquidthreads/includes/Parser.php |
— | — | @@ -1806,8 +1806,8 @@ |
1807 | 1807 | } |
1808 | 1808 | continue; |
1809 | 1809 | } elseif( $ns == NS_IMAGE ) { |
1810 | | - $img = new Image( $nt ); |
1811 | | - if( $img->exists() ) { |
| 1810 | + $img = wfFindFile( $nt ); |
| 1811 | + if( $img ) { |
1812 | 1812 | // Force a blue link if the file exists; may be a remote |
1813 | 1813 | // upload on the shared repository, and we want to see its |
1814 | 1814 | // auto-generated page. |
— | — | @@ -4393,7 +4393,7 @@ |
4394 | 4394 | ); |
4395 | 4395 | $html = $pout->getText(); |
4396 | 4396 | |
4397 | | - $ig->add( new Image( $nt ), $html ); |
| 4397 | + $ig->add( $nt, $html ); |
4398 | 4398 | |
4399 | 4399 | # Only add real images (bug #5586) |
4400 | 4400 | if ( $nt->getNamespace() == NS_IMAGE ) { |
Index: branches/liquidthreads/includes/DefaultSettings.php |
— | — | @@ -184,6 +184,49 @@ |
185 | 185 | $wgFileStore['deleted']['url'] = null; // Private |
186 | 186 | $wgFileStore['deleted']['hash'] = 3; // 3-level subdirectory split |
187 | 187 | |
| 188 | +/**#@+ |
| 189 | + * File repository structures |
| 190 | + * |
| 191 | + * $wgLocalFileRepo is a single repository structure, and $wgForeignFileRepo is |
| 192 | + * a an array of such structures. Each repository structure is an associative |
| 193 | + * array of properties configuring the repository. |
| 194 | + * |
| 195 | + * Properties required for all repos: |
| 196 | + * class The class name for the repository. May come from the core or an extension. |
| 197 | + * The core repository classes are LocalRepo, ForeignDBRepo, FSRepo. |
| 198 | + * |
| 199 | + * name A unique name for the repository. |
| 200 | + * |
| 201 | + * For all core repos: |
| 202 | + * url Base public URL |
| 203 | + * hashLevels The number of directory levels for hash-based division of files |
| 204 | + * thumbScriptUrl The URL for thumb.php (optional, not recommended) |
| 205 | + * transformVia404 Whether to skip media file transformation on parse and rely on a 404 |
| 206 | + * handler instead. |
| 207 | + * |
| 208 | + * These settings describe a foreign MediaWiki installation. They are optional, and will be ignored |
| 209 | + * for local repositories: |
| 210 | + * descBaseUrl URL of image description pages, e.g. http://en.wikipedia.org/wiki/Image: |
| 211 | + * scriptDirUrl URL of the MediaWiki installation, equivalent to $wgScriptPath, e.g. |
| 212 | + * http://en.wikipedia.org/w |
| 213 | + * |
| 214 | + * articleUrl Equivalent to $wgArticlePath, e.g. http://en.wikipedia.org/wiki/$1 |
| 215 | + * fetchDescription Fetch the text of the remote file description page. Equivalent to |
| 216 | + * $wgFetchCommonsDescriptions. |
| 217 | + * |
| 218 | + * ForeignDBRepo: |
| 219 | + * dbType, dbServer, dbUser, dbPassword, dbName, dbFlags |
| 220 | + * equivalent to the corresponding member of $wgDBservers |
| 221 | + * tablePrefix Table prefix, the foreign wiki's $wgDBprefix |
| 222 | + * hasSharedCache True if the wiki's shared cache is accessible via the local $wgMemc |
| 223 | + * |
| 224 | + * The default is to initialise these arrays from the MW<1.11 backwards compatible settings: |
| 225 | + * $wgUploadPath, $wgThumbnailScriptPath, $wgSharedUploadDirectory, etc. |
| 226 | + */ |
| 227 | +$wgLocalFileRepo = false; |
| 228 | +$wgForeignFileRepos = array(); |
| 229 | +/**#@-*/ |
| 230 | + |
188 | 231 | /** |
189 | 232 | * Allowed title characters -- regex character class |
190 | 233 | * Don't change this unless you know what you're doing |
— | — | @@ -355,6 +398,10 @@ |
356 | 399 | * no file of the given name is found in the local repository (for [[Image:..]], |
357 | 400 | * [[Media:..]] links). Thumbnails will also be looked for and generated in this |
358 | 401 | * directory. |
| 402 | + * |
| 403 | + * Note that these configuration settings can now be defined on a per- |
| 404 | + * repository basis for an arbitrary number of file repositories, using the |
| 405 | + * $wgForeignFileRepos variable. |
359 | 406 | */ |
360 | 407 | $wgUseSharedUploads = false; |
361 | 408 | /** Full path on the web server where shared uploads can be found */ |
— | — | @@ -1358,6 +1405,13 @@ |
1359 | 1406 | /** |
1360 | 1407 | * Show EXIF data, on by default if available. |
1361 | 1408 | * Requires PHP's EXIF extension: http://www.php.net/manual/en/ref.exif.php |
| 1409 | + * |
| 1410 | + * NOTE FOR WINDOWS USERS: |
| 1411 | + * To enable EXIF functions, add the folloing lines to the |
| 1412 | + * "Windows extensions" section of php.ini: |
| 1413 | + * |
| 1414 | + * extension=extensions/php_mbstring.dll |
| 1415 | + * extension=extensions/php_exif.dll |
1362 | 1416 | */ |
1363 | 1417 | $wgShowEXIF = function_exists( 'exif_read_data' ); |
1364 | 1418 | |
— | — | @@ -2008,7 +2062,13 @@ |
2009 | 2063 | * @link http://en.wikipedia.org/w/index.php?title=User%3A%C6var_Arnfj%F6r%F0_Bjarmason%2Ftestme&diff=12356041&oldid=12355864 |
2010 | 2064 | * @link http://en.wikipedia.org/wiki/Template%3AOS9 |
2011 | 2065 | */ |
2012 | | - '/^Mozilla\/4\.0 \(compatible; MSIE \d+\.\d+; Mac_PowerPC\)/' |
| 2066 | + '/^Mozilla\/4\.0 \(compatible; MSIE \d+\.\d+; Mac_PowerPC\)/', |
| 2067 | + |
| 2068 | + /** |
| 2069 | + * Google wireless transcoder, seems to eat a lot of chars alive |
| 2070 | + * http://it.wikipedia.org/w/index.php?title=Luciano_Ligabue&diff=prev&oldid=8857361 |
| 2071 | + */ |
| 2072 | + '/^Mozilla\/4\.0 \(compatible; MSIE 6.0; Windows NT 5.0; Google Wireless Transcoder;\)/' |
2013 | 2073 | ); |
2014 | 2074 | |
2015 | 2075 | /** |
Index: branches/liquidthreads/includes/SpecialMIMEsearch.php |
— | — | @@ -66,7 +66,7 @@ |
67 | 67 | $text = $wgContLang->convert( $nt->getText() ); |
68 | 68 | $plink = $skin->makeLink( $nt->getPrefixedText(), $text ); |
69 | 69 | |
70 | | - $download = $skin->makeMediaLink( $nt->getText(), 'fuck me!', wfMsgHtml( 'download' ) ); |
| 70 | + $download = $skin->makeMediaLinkObj( $nt, wfMsgHtml( 'download' ) ); |
71 | 71 | $bytes = wfMsgExt( 'nbytes', array( 'parsemag', 'escape'), |
72 | 72 | $wgLang->formatNum( $result->img_size ) ); |
73 | 73 | $dimensions = wfMsgHtml( 'widthheight', $wgLang->formatNum( $result->img_width ), |
Index: branches/liquidthreads/includes/SpecialBlockip.php |
— | — | @@ -196,7 +196,8 @@ |
197 | 197 | <td align=\"$alignRight\">{$mIpbreason}</td> |
198 | 198 | <td> |
199 | 199 | " . Xml::input( 'wpBlockReason', 45, $this->BlockReason, |
200 | | - array( 'tabindex' => '5', 'id' => 'mw-bi-reason' ) ) . " |
| 200 | + array( 'tabindex' => '5', 'id' => 'mw-bi-reason', |
| 201 | + 'maxlength'=> '200' ) ) . " |
201 | 202 | </td> |
202 | 203 | </tr> |
203 | 204 | <tr id='wpAnonOnlyRow'> |
Index: branches/liquidthreads/includes/media/DjVu.php |
— | — | @@ -69,7 +69,7 @@ |
70 | 70 | } |
71 | 71 | $width = $params['width']; |
72 | 72 | $height = $params['height']; |
73 | | - $srcPath = $image->getImagePath(); |
| 73 | + $srcPath = $image->getPath(); |
74 | 74 | $page = $params['page']; |
75 | 75 | if ( $page > $this->pageCount( $image ) ) { |
76 | 76 | return new MediaTransformError( 'thumbnail_error', $width, $height, wfMsg( 'djvu_page_error' ) ); |
Index: branches/liquidthreads/includes/media/Bitmap.php |
— | — | @@ -51,7 +51,7 @@ |
52 | 52 | $srcWidth = $image->getWidth(); |
53 | 53 | $srcHeight = $image->getHeight(); |
54 | 54 | $mimeType = $image->getMimeType(); |
55 | | - $srcPath = $image->getImagePath(); |
| 55 | + $srcPath = $image->getPath(); |
56 | 56 | $retval = 0; |
57 | 57 | wfDebug( __METHOD__.": creating {$physicalWidth}x{$physicalHeight} thumbnail at $dstPath\n" ); |
58 | 58 | |
— | — | @@ -61,7 +61,10 @@ |
62 | 62 | return new ThumbnailImage( $image->getURL(), $clientWidth, $clientHeight, $srcPath ); |
63 | 63 | } |
64 | 64 | |
65 | | - if ( $wgUseImageMagick ) { |
| 65 | + if ( !$dstPath ) { |
| 66 | + // No output path available, client side scaling only |
| 67 | + $scaler = 'client'; |
| 68 | + } elseif ( $wgUseImageMagick ) { |
66 | 69 | $scaler = 'im'; |
67 | 70 | } elseif ( $wgCustomConvertCommand ) { |
68 | 71 | $scaler = 'custom'; |
Index: branches/liquidthreads/includes/media/Generic.php |
— | — | @@ -152,7 +152,7 @@ |
153 | 153 | * Returns false if unknown or if the document is not multi-page. |
154 | 154 | */ |
155 | 155 | function getPageDimensions( $image, $page ) { |
156 | | - $gis = $this->getImageSize( $image, $image->getImagePath() ); |
| 156 | + $gis = $this->getImageSize( $image, $image->getPath() ); |
157 | 157 | return array( |
158 | 158 | 'width' => $gis[0], |
159 | 159 | 'height' => $gis[1] |
— | — | @@ -220,7 +220,7 @@ |
221 | 221 | $params['width'] = wfFitBoxWidth( $srcWidth, $srcHeight, $params['height'] ); |
222 | 222 | } |
223 | 223 | } |
224 | | - $params['height'] = Image::scaleHeight( $srcWidth, $srcHeight, $params['width'] ); |
| 224 | + $params['height'] = File::scaleHeight( $srcWidth, $srcHeight, $params['width'] ); |
225 | 225 | if ( !$this->validateThumbParams( $params['width'], $params['height'], $srcWidth, $srcHeight, $mimeType ) ) { |
226 | 226 | return false; |
227 | 227 | } |
— | — | @@ -254,7 +254,7 @@ |
255 | 255 | return false; |
256 | 256 | } |
257 | 257 | |
258 | | - $height = Image::scaleHeight( $srcWidth, $srcHeight, $width ); |
| 258 | + $height = File::scaleHeight( $srcWidth, $srcHeight, $width ); |
259 | 259 | return true; |
260 | 260 | } |
261 | 261 | |
Index: branches/liquidthreads/includes/media/SVG.php |
— | — | @@ -31,7 +31,7 @@ |
32 | 32 | $srcWidth = $image->getWidth( $params['page'] ); |
33 | 33 | $srcHeight = $image->getHeight( $params['page'] ); |
34 | 34 | $params['physicalWidth'] = $wgSVGMaxSize; |
35 | | - $params['physicalHeight'] = Image::scaleHeight( $srcWidth, $srcHeight, $wgSVGMaxSize ); |
| 35 | + $params['physicalHeight'] = File::scaleHeight( $srcWidth, $srcHeight, $wgSVGMaxSize ); |
36 | 36 | } |
37 | 37 | return true; |
38 | 38 | } |
— | — | @@ -46,7 +46,7 @@ |
47 | 47 | $clientHeight = $params['height']; |
48 | 48 | $physicalWidth = $params['physicalWidth']; |
49 | 49 | $physicalHeight = $params['physicalHeight']; |
50 | | - $srcPath = $image->getImagePath(); |
| 50 | + $srcPath = $image->getPath(); |
51 | 51 | |
52 | 52 | if ( $flags & self::TRANSFORM_LATER ) { |
53 | 53 | return new ThumbnailImage( $dstUrl, $clientWidth, $clientHeight, $dstPath ); |
Index: branches/liquidthreads/includes/normal/UtfNormal.php |
— | — | @@ -29,59 +29,6 @@ |
30 | 30 | global $utfCompatibilityDecomp; |
31 | 31 | $utfCompatibilityDecomp = NULL; |
32 | 32 | |
33 | | -define( 'UNICODE_HANGUL_FIRST', 0xac00 ); |
34 | | -define( 'UNICODE_HANGUL_LAST', 0xd7a3 ); |
35 | | - |
36 | | -define( 'UNICODE_HANGUL_LBASE', 0x1100 ); |
37 | | -define( 'UNICODE_HANGUL_VBASE', 0x1161 ); |
38 | | -define( 'UNICODE_HANGUL_TBASE', 0x11a7 ); |
39 | | - |
40 | | -define( 'UNICODE_HANGUL_LCOUNT', 19 ); |
41 | | -define( 'UNICODE_HANGUL_VCOUNT', 21 ); |
42 | | -define( 'UNICODE_HANGUL_TCOUNT', 28 ); |
43 | | -define( 'UNICODE_HANGUL_NCOUNT', UNICODE_HANGUL_VCOUNT * UNICODE_HANGUL_TCOUNT ); |
44 | | - |
45 | | -define( 'UNICODE_HANGUL_LEND', UNICODE_HANGUL_LBASE + UNICODE_HANGUL_LCOUNT - 1 ); |
46 | | -define( 'UNICODE_HANGUL_VEND', UNICODE_HANGUL_VBASE + UNICODE_HANGUL_VCOUNT - 1 ); |
47 | | -define( 'UNICODE_HANGUL_TEND', UNICODE_HANGUL_TBASE + UNICODE_HANGUL_TCOUNT - 1 ); |
48 | | - |
49 | | -define( 'UNICODE_SURROGATE_FIRST', 0xd800 ); |
50 | | -define( 'UNICODE_SURROGATE_LAST', 0xdfff ); |
51 | | -define( 'UNICODE_MAX', 0x10ffff ); |
52 | | -define( 'UNICODE_REPLACEMENT', 0xfffd ); |
53 | | - |
54 | | - |
55 | | -define( 'UTF8_HANGUL_FIRST', "\xea\xb0\x80" /*codepointToUtf8( UNICODE_HANGUL_FIRST )*/ ); |
56 | | -define( 'UTF8_HANGUL_LAST', "\xed\x9e\xa3" /*codepointToUtf8( UNICODE_HANGUL_LAST )*/ ); |
57 | | - |
58 | | -define( 'UTF8_HANGUL_LBASE', "\xe1\x84\x80" /*codepointToUtf8( UNICODE_HANGUL_LBASE )*/ ); |
59 | | -define( 'UTF8_HANGUL_VBASE', "\xe1\x85\xa1" /*codepointToUtf8( UNICODE_HANGUL_VBASE )*/ ); |
60 | | -define( 'UTF8_HANGUL_TBASE', "\xe1\x86\xa7" /*codepointToUtf8( UNICODE_HANGUL_TBASE )*/ ); |
61 | | - |
62 | | -define( 'UTF8_HANGUL_LEND', "\xe1\x84\x92" /*codepointToUtf8( UNICODE_HANGUL_LEND )*/ ); |
63 | | -define( 'UTF8_HANGUL_VEND', "\xe1\x85\xb5" /*codepointToUtf8( UNICODE_HANGUL_VEND )*/ ); |
64 | | -define( 'UTF8_HANGUL_TEND', "\xe1\x87\x82" /*codepointToUtf8( UNICODE_HANGUL_TEND )*/ ); |
65 | | - |
66 | | -define( 'UTF8_SURROGATE_FIRST', "\xed\xa0\x80" /*codepointToUtf8( UNICODE_SURROGATE_FIRST )*/ ); |
67 | | -define( 'UTF8_SURROGATE_LAST', "\xed\xbf\xbf" /*codepointToUtf8( UNICODE_SURROGATE_LAST )*/ ); |
68 | | -define( 'UTF8_MAX', "\xf4\x8f\xbf\xbf" /*codepointToUtf8( UNICODE_MAX )*/ ); |
69 | | -define( 'UTF8_REPLACEMENT', "\xef\xbf\xbd" /*codepointToUtf8( UNICODE_REPLACEMENT )*/ ); |
70 | | -#define( 'UTF8_REPLACEMENT', '!' ); |
71 | | - |
72 | | -define( 'UTF8_OVERLONG_A', "\xc1\xbf" ); |
73 | | -define( 'UTF8_OVERLONG_B', "\xe0\x9f\xbf" ); |
74 | | -define( 'UTF8_OVERLONG_C', "\xf0\x8f\xbf\xbf" ); |
75 | | - |
76 | | -# These two ranges are illegal |
77 | | -define( 'UTF8_FDD0', "\xef\xb7\x90" /*codepointToUtf8( 0xfdd0 )*/ ); |
78 | | -define( 'UTF8_FDEF', "\xef\xb7\xaf" /*codepointToUtf8( 0xfdef )*/ ); |
79 | | -define( 'UTF8_FFFE', "\xef\xbf\xbe" /*codepointToUtf8( 0xfffe )*/ ); |
80 | | -define( 'UTF8_FFFF', "\xef\xbf\xbf" /*codepointToUtf8( 0xffff )*/ ); |
81 | | - |
82 | | -define( 'UTF8_HEAD', false ); |
83 | | -define( 'UTF8_TAIL', true ); |
84 | | - |
85 | | - |
86 | 33 | /** |
87 | 34 | * For using the ICU wrapper |
88 | 35 | */ |
Index: branches/liquidthreads/includes/Skin.php |
— | — | @@ -740,8 +740,8 @@ |
741 | 741 | if ( $wgOut->isArticleRelated() ) { |
742 | 742 | if ( $wgTitle->getNamespace() == NS_IMAGE ) { |
743 | 743 | $name = $wgTitle->getDBkey(); |
744 | | - $image = new Image( $wgTitle ); |
745 | | - if( $image->exists() ) { |
| 744 | + $image = wfFindFile( $wgTitle ); |
| 745 | + if( $image ) { |
746 | 746 | $link = htmlspecialchars( $image->getURL() ); |
747 | 747 | $style = $this->getInternalLinkAttributes( $link, $name ); |
748 | 748 | $s .= " | <a href=\"{$link}\"{$style}>{$name}</a>"; |
Index: branches/liquidthreads/includes/MediaTransformOutput.php |
— | — | @@ -1,7 +1,7 @@ |
2 | 2 | <?php |
3 | 3 | |
4 | 4 | /** |
5 | | - * Base class for the output of MediaHandler::doTransform() and Image::transform(). |
| 5 | + * Base class for the output of MediaHandler::doTransform() and File::transform(). |
6 | 6 | * |
7 | 7 | * @addtogroup Media |
8 | 8 | */ |
Index: branches/liquidthreads/includes/Setup.php |
— | — | @@ -54,6 +54,59 @@ |
55 | 55 | if( $wgReadOnlyFile === false ) $wgReadOnlyFile = "{$wgUploadDirectory}/lock_yBgMBwiR"; |
56 | 56 | if( $wgFileCacheDirectory === false ) $wgFileCacheDirectory = "{$wgUploadDirectory}/cache"; |
57 | 57 | |
| 58 | +/** |
| 59 | + * Initialise $wgLocalFileRepo from backwards-compatible settings |
| 60 | + */ |
| 61 | +if ( !$wgLocalFileRepo ) { |
| 62 | + $wgLocalFileRepo = array( |
| 63 | + 'class' => 'LocalRepo', |
| 64 | + 'name' => 'local', |
| 65 | + 'directory' => $wgUploadDirectory, |
| 66 | + 'url' => $wgUploadBaseUrl ? $wgUploadBaseUrl . $wgUploadPath : $wgUploadPath, |
| 67 | + 'hashLevels' => $wgHashedUploadDirectory ? 2 : 0, |
| 68 | + 'thumbScriptUrl' => $wgThumbnailScriptPath, |
| 69 | + 'transformVia404' => !$wgGenerateThumbnailOnParse, |
| 70 | + ); |
| 71 | +} |
| 72 | +/** |
| 73 | + * Initialise shared repo from backwards-compatible settings |
| 74 | + */ |
| 75 | +if ( $wgUseSharedUploads ) { |
| 76 | + if ( $wgSharedUploadDBname ) { |
| 77 | + $wgForeignFileRepos[] = array( |
| 78 | + 'class' => 'ForeignDBRepo', |
| 79 | + 'name' => 'shared', |
| 80 | + 'directory' => $wgSharedUploadDirectory, |
| 81 | + 'url' => $wgSharedUploadPath, |
| 82 | + 'hashLevels' => $wgHashedSharedUploadDirectory ? 2 : 0, |
| 83 | + 'thumbScriptUrl' => $wgSharedThumbnailScriptPath, |
| 84 | + 'transformVia404' => !$wgGenerateThumbnailOnParse, |
| 85 | + 'dbType' => $wgDBtype, |
| 86 | + 'dbServer' => $wgDBserver, |
| 87 | + 'dbUser' => $wgDBuser, |
| 88 | + 'dbPassword' => $wgDBpassword, |
| 89 | + 'dbName' => $wgSharedUploadDBname, |
| 90 | + 'dbFlags' => DBO_DEFAULT, |
| 91 | + 'tablePrefix' => $wgSharedUploadDBprefix, |
| 92 | + 'hasSharedCache' => $wgCacheSharedUploads, |
| 93 | + 'descBaseUrl' => $wgRepositoryBaseUrl, |
| 94 | + 'fetchDescription' => $wgFetchCommonsDescriptions, |
| 95 | + ); |
| 96 | + } else { |
| 97 | + $wgForeignFileRepos[] = array( |
| 98 | + 'class' => 'FSRepo', |
| 99 | + 'name' => 'shared', |
| 100 | + 'directory' => $wgSharedUploadDirectory, |
| 101 | + 'url' => $wgSharedUploadPath, |
| 102 | + 'hashLevels' => $wgHashedSharedUploadDirectory ? 2 : 0, |
| 103 | + 'thumbScriptUrl' => $wgSharedThumbnailScriptPath, |
| 104 | + 'transformVia404' => !$wgGenerateThumbnailOnParse, |
| 105 | + 'descBaseUrl' => $wgRepositoryBaseUrl, |
| 106 | + 'fetchDescription' => $wgFetchCommonsDescriptions, |
| 107 | + ); |
| 108 | + } |
| 109 | +} |
| 110 | + |
58 | 111 | require_once( "$IP/includes/AutoLoader.php" ); |
59 | 112 | |
60 | 113 | wfProfileIn( $fname.'-exception' ); |
Index: branches/liquidthreads/includes/ImageGallery.php |
— | — | @@ -127,22 +127,26 @@ |
128 | 128 | /** |
129 | 129 | * Add an image to the gallery. |
130 | 130 | * |
131 | | - * @param $image Image object that is added to the gallery |
| 131 | + * @param $title Title object of the image that is added to the gallery |
132 | 132 | * @param $html String: additional HTML text to be shown. The name and size of the image are always shown. |
133 | 133 | */ |
134 | | - function add( $image, $html='' ) { |
135 | | - $this->mImages[] = array( &$image, $html ); |
136 | | - wfDebug( "ImageGallery::add " . $image->getName() . "\n" ); |
| 134 | + function add( $title, $html='' ) { |
| 135 | + if ( $title instanceof File ) { |
| 136 | + // Old calling convention |
| 137 | + $title = $title->getTitle(); |
| 138 | + } |
| 139 | + $this->mImages[] = array( $title, $html ); |
| 140 | + wfDebug( "ImageGallery::add " . $title->getText() . "\n" ); |
137 | 141 | } |
138 | 142 | |
139 | 143 | /** |
140 | 144 | * Add an image at the beginning of the gallery. |
141 | 145 | * |
142 | | - * @param $image Image object that is added to the gallery |
| 146 | + * @param $title Title object of the image that is added to the gallery |
143 | 147 | * @param $html String: Additional HTML text to be shown. The name and size of the image are always shown. |
144 | 148 | */ |
145 | | - function insert( $image, $html='' ) { |
146 | | - array_unshift( $this->mImages, array( &$image, $html ) ); |
| 149 | + function insert( $title, $html='' ) { |
| 150 | + array_unshift( $this->mImages, array( &$title, $html ) ); |
147 | 151 | } |
148 | 152 | |
149 | 153 | |
— | — | @@ -195,12 +199,12 @@ |
196 | 200 | $params = array( 'width' => $this->mWidths, 'height' => $this->mHeights ); |
197 | 201 | $i = 0; |
198 | 202 | foreach ( $this->mImages as $pair ) { |
199 | | - $img =& $pair[0]; |
| 203 | + $nt = $pair[0]; |
200 | 204 | $text = $pair[1]; |
201 | 205 | |
202 | | - $nt = $img->getTitle(); |
| 206 | + $img = wfFindFile( $nt ); |
203 | 207 | |
204 | | - if( $nt->getNamespace() != NS_IMAGE ) { |
| 208 | + if( $nt->getNamespace() != NS_IMAGE || !$img ) { |
205 | 209 | # We're dealing with a non-image, spit out the name and be done with it. |
206 | 210 | $thumbhtml = "\n\t\t\t".'<div style="height: '.($this->mHeights*1.25+2).'px;">' |
207 | 211 | . htmlspecialchars( $nt->getText() ) . '</div>'; |
— | — | @@ -222,7 +226,7 @@ |
223 | 227 | //$ul = $sk->makeLink( $wgContLang->getNsText( Namespace::getUser() ) . ":{$ut}", $ut ); |
224 | 228 | |
225 | 229 | if( $this->mShowBytes ) { |
226 | | - if( $img->exists() ) { |
| 230 | + if( $img ) { |
227 | 231 | $nb = wfMsgExt( 'nbytes', array( 'parsemag', 'escape'), |
228 | 232 | $wgLang->formatNum( $img->getSize() ) ); |
229 | 233 | } else { |
Index: branches/liquidthreads/includes/Defines.php |
— | — | @@ -205,5 +205,61 @@ |
206 | 206 | define( 'LIST_NAMES', 3); |
207 | 207 | define( 'LIST_OR', 4); |
208 | 208 | |
| 209 | +/** |
| 210 | + * Unicode and normalisation related |
| 211 | + */ |
| 212 | +define( 'UNICODE_HANGUL_FIRST', 0xac00 ); |
| 213 | +define( 'UNICODE_HANGUL_LAST', 0xd7a3 ); |
209 | 214 | |
| 215 | +define( 'UNICODE_HANGUL_LBASE', 0x1100 ); |
| 216 | +define( 'UNICODE_HANGUL_VBASE', 0x1161 ); |
| 217 | +define( 'UNICODE_HANGUL_TBASE', 0x11a7 ); |
| 218 | + |
| 219 | +define( 'UNICODE_HANGUL_LCOUNT', 19 ); |
| 220 | +define( 'UNICODE_HANGUL_VCOUNT', 21 ); |
| 221 | +define( 'UNICODE_HANGUL_TCOUNT', 28 ); |
| 222 | +define( 'UNICODE_HANGUL_NCOUNT', UNICODE_HANGUL_VCOUNT * UNICODE_HANGUL_TCOUNT ); |
| 223 | + |
| 224 | +define( 'UNICODE_HANGUL_LEND', UNICODE_HANGUL_LBASE + UNICODE_HANGUL_LCOUNT - 1 ); |
| 225 | +define( 'UNICODE_HANGUL_VEND', UNICODE_HANGUL_VBASE + UNICODE_HANGUL_VCOUNT - 1 ); |
| 226 | +define( 'UNICODE_HANGUL_TEND', UNICODE_HANGUL_TBASE + UNICODE_HANGUL_TCOUNT - 1 ); |
| 227 | + |
| 228 | +define( 'UNICODE_SURROGATE_FIRST', 0xd800 ); |
| 229 | +define( 'UNICODE_SURROGATE_LAST', 0xdfff ); |
| 230 | +define( 'UNICODE_MAX', 0x10ffff ); |
| 231 | +define( 'UNICODE_REPLACEMENT', 0xfffd ); |
| 232 | + |
| 233 | + |
| 234 | +define( 'UTF8_HANGUL_FIRST', "\xea\xb0\x80" /*codepointToUtf8( UNICODE_HANGUL_FIRST )*/ ); |
| 235 | +define( 'UTF8_HANGUL_LAST', "\xed\x9e\xa3" /*codepointToUtf8( UNICODE_HANGUL_LAST )*/ ); |
| 236 | + |
| 237 | +define( 'UTF8_HANGUL_LBASE', "\xe1\x84\x80" /*codepointToUtf8( UNICODE_HANGUL_LBASE )*/ ); |
| 238 | +define( 'UTF8_HANGUL_VBASE', "\xe1\x85\xa1" /*codepointToUtf8( UNICODE_HANGUL_VBASE )*/ ); |
| 239 | +define( 'UTF8_HANGUL_TBASE', "\xe1\x86\xa7" /*codepointToUtf8( UNICODE_HANGUL_TBASE )*/ ); |
| 240 | + |
| 241 | +define( 'UTF8_HANGUL_LEND', "\xe1\x84\x92" /*codepointToUtf8( UNICODE_HANGUL_LEND )*/ ); |
| 242 | +define( 'UTF8_HANGUL_VEND', "\xe1\x85\xb5" /*codepointToUtf8( UNICODE_HANGUL_VEND )*/ ); |
| 243 | +define( 'UTF8_HANGUL_TEND', "\xe1\x87\x82" /*codepointToUtf8( UNICODE_HANGUL_TEND )*/ ); |
| 244 | + |
| 245 | +define( 'UTF8_SURROGATE_FIRST', "\xed\xa0\x80" /*codepointToUtf8( UNICODE_SURROGATE_FIRST )*/ ); |
| 246 | +define( 'UTF8_SURROGATE_LAST', "\xed\xbf\xbf" /*codepointToUtf8( UNICODE_SURROGATE_LAST )*/ ); |
| 247 | +define( 'UTF8_MAX', "\xf4\x8f\xbf\xbf" /*codepointToUtf8( UNICODE_MAX )*/ ); |
| 248 | +define( 'UTF8_REPLACEMENT', "\xef\xbf\xbd" /*codepointToUtf8( UNICODE_REPLACEMENT )*/ ); |
| 249 | +#define( 'UTF8_REPLACEMENT', '!' ); |
| 250 | + |
| 251 | +define( 'UTF8_OVERLONG_A', "\xc1\xbf" ); |
| 252 | +define( 'UTF8_OVERLONG_B', "\xe0\x9f\xbf" ); |
| 253 | +define( 'UTF8_OVERLONG_C', "\xf0\x8f\xbf\xbf" ); |
| 254 | + |
| 255 | +# These two ranges are illegal |
| 256 | +define( 'UTF8_FDD0', "\xef\xb7\x90" /*codepointToUtf8( 0xfdd0 )*/ ); |
| 257 | +define( 'UTF8_FDEF', "\xef\xb7\xaf" /*codepointToUtf8( 0xfdef )*/ ); |
| 258 | +define( 'UTF8_FFFE', "\xef\xbf\xbe" /*codepointToUtf8( 0xfffe )*/ ); |
| 259 | +define( 'UTF8_FFFF', "\xef\xbf\xbf" /*codepointToUtf8( 0xffff )*/ ); |
| 260 | + |
| 261 | +define( 'UTF8_HEAD', false ); |
| 262 | +define( 'UTF8_TAIL', true ); |
| 263 | + |
| 264 | + |
| 265 | + |
210 | 266 | ?> |
Index: branches/liquidthreads/includes/SpecialNewimages.php |
— | — | @@ -135,10 +135,9 @@ |
136 | 136 | $ut = $s->img_user_text; |
137 | 137 | |
138 | 138 | $nt = Title::newFromText( $name, NS_IMAGE ); |
139 | | - $img = new Image( $nt ); |
140 | 139 | $ul = $sk->makeLinkObj( Title::makeTitle( NS_USER, $ut ), $ut ); |
141 | 140 | |
142 | | - $gallery->add( $img, "$ul<br />\n<i>".$wgLang->timeanddate( $s->img_timestamp, true )."</i><br />\n" ); |
| 141 | + $gallery->add( $nt, "$ul<br />\n<i>".$wgLang->timeanddate( $s->img_timestamp, true )."</i><br />\n" ); |
143 | 142 | |
144 | 143 | $timestamp = wfTimestamp( TS_MW, $s->img_timestamp ); |
145 | 144 | if( empty( $firstTimestamp ) ) { |
Index: branches/liquidthreads/includes/SpecialUpload.php |
— | — | @@ -27,6 +27,7 @@ |
28 | 28 | var $mUploadCopyStatus, $mUploadSource, $mReUpload, $mAction, $mUpload; |
29 | 29 | var $mOname, $mSessionKey, $mStashed, $mDestFile, $mRemoveTempFile, $mSourceType; |
30 | 30 | var $mUploadTempFileSize = 0; |
| 31 | + var $mImage; |
31 | 32 | |
32 | 33 | # Placeholders for text injection by hooks (must be HTML) |
33 | 34 | # extensions should take care to _append_ to the present value |
— | — | @@ -412,13 +413,13 @@ |
413 | 414 | |
414 | 415 | global $wgUser; |
415 | 416 | $sk = $wgUser->getSkin(); |
416 | | - $image = new Image( $nt ); |
| 417 | + $image = wfLocalFile( $nt ); |
417 | 418 | |
418 | 419 | // Check for uppercase extension. We allow these filenames but check if an image |
419 | 420 | // with lowercase extension exists already |
420 | 421 | if ( $finalExt != strtolower( $finalExt ) ) { |
421 | 422 | $nt_lc = Title::newFromText( $partname . '.' . strtolower( $finalExt ) ); |
422 | | - $image_lc = new Image( $nt_lc ); |
| 423 | + $image_lc = wfLocalFile( $nt_lc ); |
423 | 424 | } |
424 | 425 | |
425 | 426 | if( $image->exists() ) { |
— | — | @@ -452,7 +453,7 @@ |
453 | 454 | } elseif ( ( substr( $partname , 3, 3 ) == 'px-' || substr( $partname , 2, 3 ) == 'px-' ) && ereg( "[0-9]{2}" , substr( $partname , 0, 2) ) ) { |
454 | 455 | # Check for filenames like 50px- or 180px-, these are mostly thumbnails |
455 | 456 | $nt_thb = Title::newFromText( substr( $partname , strpos( $partname , '-' ) +1 ) . '.' . $finalExt ); |
456 | | - $image_thb = new Image( $nt_thb ); |
| 457 | + $image_thb = wfLocalFile( $nt_thb ); |
457 | 458 | if ($image_thb->exists() ) { |
458 | 459 | # Check if an image without leading '180px-' (or similiar) exists |
459 | 460 | $dlink = $sk->makeKnownLinkObj( $nt_thb); |
— | — | @@ -500,8 +501,8 @@ |
501 | 502 | * Update the upload log and create the description page |
502 | 503 | * if it's a new file. |
503 | 504 | */ |
504 | | - $img = Image::newFromName( $this->mUploadSaveName ); |
505 | | - $success = $img->recordUpload( $this->mUploadOldVersion, |
| 505 | + $this->mImage = wfLocalFile( $this->mUploadSaveName ); |
| 506 | + $success = $this->mImage->recordUpload( $this->mUploadOldVersion, |
506 | 507 | $this->mUploadDescription, |
507 | 508 | $this->mLicense, |
508 | 509 | $this->mUploadCopyStatus, |
— | — | @@ -512,7 +513,7 @@ |
513 | 514 | $this->showSuccess(); |
514 | 515 | wfRunHooks( 'UploadComplete', array( &$img ) ); |
515 | 516 | } else { |
516 | | - // Image::recordUpload() fails if the image went missing, which is |
| 517 | + // File::recordUpload() fails if the image went missing, which is |
517 | 518 | // unlikely, hence the lack of a specialised message |
518 | 519 | $wgOut->showFileNotFoundError( $this->mUploadSaveName ); |
519 | 520 | } |
— | — | @@ -534,48 +535,13 @@ |
535 | 536 | function saveUploadedFile( $saveName, $tempName, $useRename = false ) { |
536 | 537 | global $wgOut, $wgAllowCopyUploads; |
537 | 538 | |
538 | | - if ( !$useRename AND $wgAllowCopyUploads AND $this->mSourceType == 'web' ) $useRename = true; |
539 | | - |
540 | | - $fname= "SpecialUpload::saveUploadedFile"; |
541 | | - |
542 | | - $dest = wfImageDir( $saveName ); |
543 | | - $archive = wfImageArchiveDir( $saveName ); |
544 | | - if ( !is_dir( $dest ) ) wfMkdirParents( $dest ); |
545 | | - if ( !is_dir( $archive ) ) wfMkdirParents( $archive ); |
546 | | - |
547 | | - $this->mSavedFile = "{$dest}/{$saveName}"; |
548 | | - |
549 | | - if( is_file( $this->mSavedFile ) ) { |
550 | | - $this->mUploadOldVersion = gmdate( 'YmdHis' ) . "!{$saveName}"; |
551 | | - wfSuppressWarnings(); |
552 | | - $success = rename( $this->mSavedFile, "${archive}/{$this->mUploadOldVersion}" ); |
553 | | - wfRestoreWarnings(); |
554 | | - |
555 | | - if( ! $success ) { |
556 | | - $wgOut->showFileRenameError( $this->mSavedFile, |
557 | | - "${archive}/{$this->mUploadOldVersion}" ); |
558 | | - return false; |
559 | | - } |
560 | | - else wfDebug("$fname: moved file ".$this->mSavedFile." to ${archive}/{$this->mUploadOldVersion}\n"); |
561 | | - } |
562 | | - else { |
563 | | - $this->mUploadOldVersion = ''; |
564 | | - } |
565 | | - |
566 | | - wfSuppressWarnings(); |
567 | | - $success = $useRename |
568 | | - ? rename( $tempName, $this->mSavedFile ) |
569 | | - : move_uploaded_file( $tempName, $this->mSavedFile ); |
570 | | - wfRestoreWarnings(); |
571 | | - |
572 | | - if( ! $success ) { |
573 | | - $wgOut->showFileCopyError( $tempName, $this->mSavedFile ); |
| 539 | + $image = wfLocalFile( $saveName ); |
| 540 | + $archiveName = $image->publish( $tempName, File::DELETE_SOURCE ); |
| 541 | + if ( WikiError::isError( $archiveName ) ) { |
| 542 | + $this->showError( $archiveName ); |
574 | 543 | return false; |
575 | | - } else { |
576 | | - wfDebug("$fname: wrote tempfile $tempName to ".$this->mSavedFile."\n"); |
577 | 544 | } |
578 | | - |
579 | | - chmod( $this->mSavedFile, 0644 ); |
| 545 | + $this->mUploadOldVersion = $archiveName; |
580 | 546 | return true; |
581 | 547 | } |
582 | 548 | |
— | — | @@ -593,19 +559,14 @@ |
594 | 560 | */ |
595 | 561 | function saveTempUploadedFile( $saveName, $tempName ) { |
596 | 562 | global $wgOut; |
597 | | - $archive = wfImageArchiveDir( $saveName, 'temp' ); |
598 | | - if ( !is_dir ( $archive ) ) wfMkdirParents( $archive ); |
599 | | - $stash = $archive . '/' . gmdate( "YmdHis" ) . '!' . $saveName; |
600 | | - |
601 | | - $success = $this->mRemoveTempFile |
602 | | - ? rename( $tempName, $stash ) |
603 | | - : move_uploaded_file( $tempName, $stash ); |
604 | | - if ( !$success ) { |
605 | | - $wgOut->showFileCopyError( $tempName, $stash ); |
| 563 | + $repo = RepoGroup::singleton()->getLocalRepo(); |
| 564 | + $result = $repo->storeTemp( $saveName, $tempName ); |
| 565 | + if ( WikiError::isError( $result ) ) { |
| 566 | + $this->showError( $result ); |
606 | 567 | return false; |
| 568 | + } else { |
| 569 | + return $result; |
607 | 570 | } |
608 | | - |
609 | | - return $stash; |
610 | 571 | } |
611 | 572 | |
612 | 573 | /** |
— | — | @@ -662,7 +623,7 @@ |
663 | 624 | global $wgUser, $wgOut, $wgContLang; |
664 | 625 | |
665 | 626 | $sk = $wgUser->getSkin(); |
666 | | - $ilink = $sk->makeMediaLink( $this->mUploadSaveName, Image::imageUrl( $this->mUploadSaveName ) ); |
| 627 | + $ilink = $sk->makeMediaLinkObj( $this->mImage->getTitle() ); |
667 | 628 | $dname = $wgContLang->getNsText( NS_IMAGE ) . ':'.$this->mUploadSaveName; |
668 | 629 | $dlink = $sk->makeKnownLink( $dname, $dname ); |
669 | 630 | |
— | — | @@ -1274,15 +1235,10 @@ |
1275 | 1236 | * @access private |
1276 | 1237 | */ |
1277 | 1238 | function checkOverwrite( $name ) { |
1278 | | - $img = Image::newFromName( $name ); |
1279 | | - if( is_null( $img ) ) { |
1280 | | - // Uh... this shouldn't happen ;) |
1281 | | - // But if it does, fall through to previous behavior |
1282 | | - return false; |
1283 | | - } |
| 1239 | + $img = wfFindFile( $name ); |
1284 | 1240 | |
1285 | 1241 | $error = ''; |
1286 | | - if( $img->exists() ) { |
| 1242 | + if( $img ) { |
1287 | 1243 | global $wgUser, $wgOut; |
1288 | 1244 | if( $img->isLocal() ) { |
1289 | 1245 | if( !self::userCanReUpload( $wgUser, $img->name ) ) { |
— | — | @@ -1328,5 +1284,17 @@ |
1329 | 1285 | |
1330 | 1286 | return $user->getID() == $row->img_user; |
1331 | 1287 | } |
| 1288 | + |
| 1289 | + /** |
| 1290 | + * Display an error from a wikitext-formatted WikiError object |
| 1291 | + */ |
| 1292 | + function showError( WikiError $error ) { |
| 1293 | + global $wgOut; |
| 1294 | + $wgOut->setPageTitle( wfMsg( "internalerror" ) ); |
| 1295 | + $wgOut->setRobotpolicy( "noindex,nofollow" ); |
| 1296 | + $wgOut->setArticleRelated( false ); |
| 1297 | + $wgOut->enableClientCache( false ); |
| 1298 | + $wgOut->addWikiText( $error->getMessage() ); |
| 1299 | + } |
1332 | 1300 | } |
1333 | 1301 | ?> |
Index: branches/liquidthreads/includes/GlobalFunctions.php |
— | — | @@ -2272,4 +2272,26 @@ |
2273 | 2273 | $ret = $wgLoadBalancer->getConnection( $db, true, $groups ); |
2274 | 2274 | return $ret; |
2275 | 2275 | } |
| 2276 | + |
| 2277 | +/** |
| 2278 | + * Find a file. |
| 2279 | + * Shortcut for RepoGroup::singleton()->findFile() |
| 2280 | + * @param mixed $title Title object or string. May be interwiki. |
| 2281 | + * @param mixed $time Requested time for an archived image, or false for the |
| 2282 | + * current version. An image object will be returned which |
| 2283 | + * existed at or before the specified time. |
| 2284 | + * @return File, or false if the file does not exist |
| 2285 | + */ |
| 2286 | +function wfFindFile( $title, $time = false ) { |
| 2287 | + return RepoGroup::singleton()->findFile( $title, $time ); |
| 2288 | +} |
| 2289 | + |
| 2290 | +/** |
| 2291 | + * Get an object referring to a locally registered file. |
| 2292 | + * Returns a valid placeholder object if the file does not exist. |
| 2293 | + */ |
| 2294 | +function wfLocalFile( $title ) { |
| 2295 | + return RepoGroup::singleton()->getLocalRepo()->newFile( $title ); |
| 2296 | +} |
| 2297 | + |
2276 | 2298 | ?> |
Index: branches/liquidthreads/includes/CategoryPage.php |
— | — | @@ -147,7 +147,7 @@ |
148 | 148 | /** |
149 | 149 | * Add a page in the image namespace |
150 | 150 | */ |
151 | | - function addImage( $title, $sortkey, $pageLength, $isRedirect = false ) { |
| 151 | + function addImage( Title $title, $sortkey, $pageLength, $isRedirect = false ) { |
152 | 152 | if ( $this->showGallery ) { |
153 | 153 | $image = new Image( $title ); |
154 | 154 | if( $this->flip ) { |
— | — | @@ -222,7 +222,7 @@ |
223 | 223 | |
224 | 224 | if( $title->getNamespace() == NS_CATEGORY ) { |
225 | 225 | $this->addSubcategory( $title, $x->cl_sortkey, $x->page_len ); |
226 | | - } elseif( $title->getNamespace() == NS_IMAGE ) { |
| 226 | + } elseif( $this->showGallery && $title->getNamespace() == NS_IMAGE ) { |
227 | 227 | $this->addImage( $title, $x->cl_sortkey, $x->page_len, $x->page_is_redirect ); |
228 | 228 | } else { |
229 | 229 | $this->addPage( $title, $x->cl_sortkey, $x->page_len, $x->page_is_redirect ); |
Index: branches/liquidthreads/includes/ImageFunctions.php |
— | — | @@ -1,114 +1,5 @@ |
2 | 2 | <?php |
3 | | - |
4 | 3 | /** |
5 | | - * Returns the image directory of an image |
6 | | - * The result is an absolute path. |
7 | | - * |
8 | | - * This function is called from thumb.php before Setup.php is included |
9 | | - * |
10 | | - * @param $fname String: file name of the image file. |
11 | | - * @public |
12 | | - */ |
13 | | -function wfImageDir( $fname ) { |
14 | | - global $wgUploadDirectory, $wgHashedUploadDirectory; |
15 | | - |
16 | | - if (!$wgHashedUploadDirectory) { return $wgUploadDirectory; } |
17 | | - |
18 | | - $hash = md5( $fname ); |
19 | | - $dest = $wgUploadDirectory . '/' . $hash{0} . '/' . substr( $hash, 0, 2 ); |
20 | | - |
21 | | - return $dest; |
22 | | -} |
23 | | - |
24 | | -/** |
25 | | - * Returns the image directory of an image's thumbnail |
26 | | - * The result is an absolute path. |
27 | | - * |
28 | | - * This function is called from thumb.php before Setup.php is included |
29 | | - * |
30 | | - * @param $fname String: file name of the original image file |
31 | | - * @param $shared Boolean: (optional) use the shared upload directory (default: 'false'). |
32 | | - * @public |
33 | | - */ |
34 | | -function wfImageThumbDir( $fname, $shared = false ) { |
35 | | - $base = wfImageArchiveDir( $fname, 'thumb', $shared ); |
36 | | - if ( Image::isHashed( $shared ) ) { |
37 | | - $dir = "$base/$fname"; |
38 | | - } else { |
39 | | - $dir = $base; |
40 | | - } |
41 | | - |
42 | | - return $dir; |
43 | | -} |
44 | | - |
45 | | -/** |
46 | | - * Old thumbnail directory, kept for conversion |
47 | | - */ |
48 | | -function wfDeprecatedThumbDir( $thumbName , $subdir='thumb', $shared=false) { |
49 | | - return wfImageArchiveDir( $thumbName, $subdir, $shared ); |
50 | | -} |
51 | | - |
52 | | -/** |
53 | | - * Returns the image directory of an image's old version |
54 | | - * The result is an absolute path. |
55 | | - * |
56 | | - * This function is called from thumb.php before Setup.php is included |
57 | | - * |
58 | | - * @param $fname String: file name of the thumbnail file, including file size prefix. |
59 | | - * @param $subdir String: subdirectory of the image upload directory that should be used for storing the old version. Default is 'archive'. |
60 | | - * @param $shared Boolean use the shared upload directory (only relevant for other functions which call this one). Default is 'false'. |
61 | | - * @public |
62 | | - */ |
63 | | -function wfImageArchiveDir( $fname , $subdir='archive', $shared=false ) { |
64 | | - global $wgUploadDirectory, $wgHashedUploadDirectory; |
65 | | - global $wgSharedUploadDirectory, $wgHashedSharedUploadDirectory; |
66 | | - $dir = $shared ? $wgSharedUploadDirectory : $wgUploadDirectory; |
67 | | - $hashdir = $shared ? $wgHashedSharedUploadDirectory : $wgHashedUploadDirectory; |
68 | | - if (!$hashdir) { return $dir.'/'.$subdir; } |
69 | | - $hash = md5( $fname ); |
70 | | - |
71 | | - return $dir.'/'.$subdir.'/'.$hash[0].'/'.substr( $hash, 0, 2 ); |
72 | | -} |
73 | | - |
74 | | - |
75 | | -/* |
76 | | - * Return the hash path component of an image path (URL or filesystem), |
77 | | - * e.g. "/3/3c/", or just "/" if hashing is not used. |
78 | | - * |
79 | | - * @param $dbkey The filesystem / database name of the file |
80 | | - * @param $fromSharedDirectory Use the shared file repository? It may |
81 | | - * use different hash settings from the local one. |
82 | | - */ |
83 | | -function wfGetHashPath ( $dbkey, $fromSharedDirectory = false ) { |
84 | | - if( Image::isHashed( $fromSharedDirectory ) ) { |
85 | | - $hash = md5($dbkey); |
86 | | - return '/' . $hash{0} . '/' . substr( $hash, 0, 2 ) . '/'; |
87 | | - } else { |
88 | | - return '/'; |
89 | | - } |
90 | | -} |
91 | | - |
92 | | -/** |
93 | | - * Returns the image URL of an image's old version |
94 | | - * |
95 | | - * @param $name String: file name of the image file |
96 | | - * @param $subdir String: (optional) subdirectory of the image upload directory that is used by the old version. Default is 'archive' |
97 | | - * @public |
98 | | - */ |
99 | | -function wfImageArchiveUrl( $name, $subdir='archive' ) { |
100 | | - global $wgUploadPath, $wgHashedUploadDirectory; |
101 | | - |
102 | | - if ($wgHashedUploadDirectory) { |
103 | | - $hash = md5( substr( $name, 15) ); |
104 | | - $url = $wgUploadPath.'/'.$subdir.'/' . $hash{0} . '/' . |
105 | | - substr( $hash, 0, 2 ) . '/'.$name; |
106 | | - } else { |
107 | | - $url = $wgUploadPath.'/'.$subdir.'/'.$name; |
108 | | - } |
109 | | - return wfUrlencode($url); |
110 | | -} |
111 | | - |
112 | | -/** |
113 | 4 | * Return a rounded pixel equivalent for a labeled CSS/SVG length. |
114 | 5 | * http://www.w3.org/TR/SVG11/coords.html#UnitIdentifiers |
115 | 6 | * |
Index: branches/liquidthreads/includes/SpecialImagelist.php |
— | — | @@ -115,7 +115,9 @@ |
116 | 116 | case 'img_name': |
117 | 117 | $name = $this->mCurrentRow->img_name; |
118 | 118 | $link = $this->getSkin()->makeKnownLinkObj( Title::makeTitle( NS_IMAGE, $name ), $value ); |
119 | | - $download = Xml::element('a', array( "href" => Image::imageUrl( $name ) ), $this->mMessages['imgfile'] ); |
| 119 | + $image = wfLocalFile( $value ); |
| 120 | + $url = $image->getURL(); |
| 121 | + $download = Xml::element('a', array( "href" => $url ), $this->mMessages['imgfile'] ); |
120 | 122 | return "$link ($download)"; |
121 | 123 | case 'img_user_text': |
122 | 124 | if ( $this->mCurrentRow->img_user ) { |
Index: branches/liquidthreads/StartProfiler.php |
— | — | @@ -1,22 +1,24 @@ |
2 | 2 | <?php |
3 | 3 | |
4 | | -require_once( dirname(__FILE__).'/includes/ProfilerStub.php' ); |
| 4 | +#require_once( './includes/ProfilerStub.php' ); |
5 | 5 | |
6 | 6 | /** |
7 | 7 | * To use a profiler, delete the line above and add something like this: |
8 | 8 | * |
9 | | - * require_once( dirname(__FILE__).'/includes/Profiler.php' ); |
| 9 | + * require_once( './includes/Profiler.php' ); |
10 | 10 | * $wgProfiler = new Profiler; |
11 | 11 | * |
12 | 12 | * Or for a sampling profiler: |
13 | 13 | * if ( !mt_rand( 0, 100 ) ) { |
14 | | - * require_once( dirname(__FILE__).'/includes/Profiler.php' ); |
| 14 | + * require_once( './includes/Profiler.php' ); |
15 | 15 | * $wgProfiler = new Profiler; |
16 | 16 | * } else { |
17 | | - * require_once( dirname(__FILE__).'/includes/ProfilerStub.php' ); |
| 17 | + * require_once( './includes/ProfilerStub.php' ); |
18 | 18 | * } |
19 | 19 | * |
20 | 20 | * Configuration of the profiler output can be done in LocalSettings.php |
21 | 21 | */ |
| 22 | +require_once( dirname(__FILE__).'/includes/Profiler.php' ); |
| 23 | +$wgProfiler = new Profiler; |
22 | 24 | |
23 | 25 | ?> |
Index: branches/liquidthreads/thumb.php |
— | — | @@ -2,20 +2,15 @@ |
3 | 3 | |
4 | 4 | /** |
5 | 5 | * PHP script to stream out an image thumbnail. |
6 | | - * If the file exists, we make do with abridged MediaWiki initialisation. |
7 | 6 | */ |
8 | | -define( 'MW_NO_SETUP', 1 ); |
9 | 7 | define( 'MW_NO_OUTPUT_COMPRESSION', 1 ); |
10 | 8 | require_once( './includes/WebStart.php' ); |
11 | 9 | wfProfileIn( 'thumb.php' ); |
12 | 10 | wfProfileIn( 'thumb.php-start' ); |
13 | | -require_once( "$IP/includes/GlobalFunctions.php" ); |
14 | | -require_once( "$IP/includes/ImageFunctions.php" ); |
15 | 11 | |
16 | 12 | $wgTrivialMimeDetection = true; //don't use fancy mime detection, just check the file extension for jpg/gif/png. |
17 | 13 | |
18 | 14 | require_once( "$IP/includes/StreamFile.php" ); |
19 | | -require_once( "$IP/includes/AutoLoader.php" ); |
20 | 15 | |
21 | 16 | // Get input parameters |
22 | 17 | if ( get_magic_quotes_gpc() ) { |
— | — | @@ -40,36 +35,30 @@ |
41 | 36 | // Some basic input validation |
42 | 37 | $fileName = strtr( $fileName, '\\/', '__' ); |
43 | 38 | |
44 | | -// Work out paths, carefully avoiding constructing an Image object because that won't work yet |
| 39 | +// Stream the file if it exists already |
45 | 40 | try { |
46 | | - $handler = thumbGetHandler( $fileName ); |
47 | | - if ( $handler ) { |
48 | | - $imagePath = wfImageDir( $fileName ) . '/' . $fileName; |
49 | | - $thumbName = $handler->makeParamString( $params ) . "-$fileName"; |
50 | | - $thumbPath = wfImageThumbDir( $fileName ) . '/' . $thumbName; |
| 41 | + $img = wfLocalFile( $fileName ); |
| 42 | + if ( $img && false != ( $thumbName = $img->thumbName( $params ) ) ) { |
| 43 | + $thumbPath = $img->getThumbPath( $thumbName ); |
51 | 44 | |
52 | | - if ( is_file( $thumbPath ) && filemtime( $thumbPath ) >= filemtime( $imagePath ) ) { |
| 45 | + if ( is_file( $thumbPath ) ) { |
53 | 46 | wfStreamFile( $thumbPath ); |
54 | | - // Can't log profiling data with no Setup.php |
| 47 | + wfLogProfilingData(); |
55 | 48 | exit; |
56 | 49 | } |
57 | 50 | } |
58 | 51 | } catch ( MWException $e ) { |
59 | | - require_once( './includes/Setup.php' ); |
60 | 52 | thumbInternalError( $e->getHTML() ); |
| 53 | + wfLogProfilingData(); |
61 | 54 | exit; |
62 | 55 | } |
63 | 56 | |
64 | | - |
65 | | -// OK, no valid thumbnail, time to get out the heavy machinery |
66 | 57 | wfProfileOut( 'thumb.php-start' ); |
67 | | -require_once( './includes/Setup.php' ); |
68 | 58 | wfProfileIn( 'thumb.php-render' ); |
69 | 59 | |
70 | | -$img = Image::newFromName( $fileName ); |
71 | 60 | try { |
72 | 61 | if ( $img ) { |
73 | | - $thumb = $img->transform( $params, Image::RENDER_NOW ); |
| 62 | + $thumb = $img->transform( $params, File::RENDER_NOW ); |
74 | 63 | } else { |
75 | 64 | $thumb = false; |
76 | 65 | } |
— | — | @@ -80,9 +69,11 @@ |
81 | 70 | |
82 | 71 | if ( $thumb && $thumb->getPath() && file_exists( $thumb->getPath() ) ) { |
83 | 72 | wfStreamFile( $thumb->getPath() ); |
84 | | -} elseif ( $img ) { |
85 | | - if ( !$thumb ) { |
86 | | - $msg = wfMsgHtml( 'thumbnail_error', 'Image::transform() returned false' ); |
| 73 | +} else { |
| 74 | + if ( !$img ) { |
| 75 | + $msg = wfMsg( 'badtitletext' ); |
| 76 | + } elseif ( !$thumb ) { |
| 77 | + $msg = wfMsgHtml( 'thumbnail_error', 'File::transform() returned false' ); |
87 | 78 | } elseif ( $thumb->isError() ) { |
88 | 79 | $msg = $thumb->getHtmlMsg(); |
89 | 80 | } elseif ( !$thumb->getPath() ) { |
— | — | @@ -91,19 +82,6 @@ |
92 | 83 | $msg = wfMsgHtml( 'thumbnail_error', 'Output file missing' ); |
93 | 84 | } |
94 | 85 | thumbInternalError( $msg ); |
95 | | -} else { |
96 | | - $badtitle = wfMsg( 'badtitle' ); |
97 | | - $badtitletext = wfMsg( 'badtitletext' ); |
98 | | - header( 'Cache-Control: no-cache' ); |
99 | | - header( 'Content-Type: text/html; charset=utf-8' ); |
100 | | - header( 'HTTP/1.1 500 Internal server error' ); |
101 | | - echo "<html><head> |
102 | | - <title>$badtitle</title> |
103 | | - <body> |
104 | | -<h1>$badtitle</h1> |
105 | | -<p>$badtitletext</p> |
106 | | -</body></html> |
107 | | -"; |
108 | 86 | } |
109 | 87 | |
110 | 88 | wfProfileOut( 'thumb.php-render' ); |
— | — | @@ -112,17 +90,6 @@ |
113 | 91 | |
114 | 92 | //-------------------------------------------------------------------------- |
115 | 93 | |
116 | | -function thumbGetHandler( $fileName ) { |
117 | | - // Determine type |
118 | | - $magic = MimeMagic::singleton(); |
119 | | - $extPos = strrpos( $fileName, '.' ); |
120 | | - if ( $extPos === false ) { |
121 | | - return false; |
122 | | - } |
123 | | - $mime = $magic->guessTypesForExtension( substr( $fileName, $extPos + 1 ) ); |
124 | | - return MediaHandler::getHandler( $mime ); |
125 | | -} |
126 | | - |
127 | 94 | function thumbInternalError( $msg ) { |
128 | 95 | header( 'Cache-Control: no-cache' ); |
129 | 96 | header( 'Content-Type: text/html; charset=utf-8' ); |
Index: branches/liquidthreads/languages/messages/MessagesFiu_vro.php |
— | — | @@ -390,7 +390,6 @@ |
391 | 391 | 'yournick' => 'Suq kutsmisnimi (alakirotamisõs)', |
392 | 392 | 'badsig' => 'Seo alakirotus olõ-i masva.', |
393 | 393 | 'email' => 'e-posti aadrõs', |
394 | | -'prefs-help-email-enotif' => 'Taad aadrõsi pääle saadõtasõq sullõ ka artiklidõ muutumisteedüseq, ku sa sääntseq säädmiseq käüki võtat.', |
395 | 394 | 'prefs-help-realname' => "* <strong>Peris nimi</strong> (piä-i kirotama): ku taa teedäq annat, sis pruugitas taad pruukjanime asõmõl lehekülgi tegijide nimekir'on.", |
396 | 395 | 'loginerror' => 'Sisseminemise viga', |
397 | 396 | 'prefs-help-email' => '* <strong>E-post</strong> (piä-i kirotama): tõõsõq pruukjaq saavaq sullõ kirotaq ilma su aadrõssit nägemäldäq. Taast om sis kah kassu, ku uma salasõna ärq johtut unõhtama.', |
— | — | @@ -481,6 +480,19 @@ |
482 | 481 | Panõq tähele, et sa saa-i taalõ pruukjalõ sõnomit saataq, ku sa olõ-i kirjä pandnuq umma [[Special:Preferences|säädmislehe]] e-posti aadrõssit. |
483 | 482 | |
484 | 483 | Suq puutri võrgoaadrõs om $3 ja kinnipandmistunnus om #$5. Panõq naaq kõiki perräküsümiisi manoq, midä tiit.", |
| 484 | +'autoblockedtext' => "Su puutri võrgoaadrõs peeti automaatsõhe kinniq, selle et taad om tarvitanuq kiäki pruukja, kink om kinniq pidänüq $1. |
| 485 | +Kinniqpidämise põhjus: |
| 486 | + |
| 487 | +:''$2'' |
| 488 | + |
| 489 | +Kinniqpidämise aig: $6 |
| 490 | + |
| 491 | +Taa kinniqpidämise kotsilõ perräküsümises ja taa arotamisõs võit kirotaq kõrraldajalõ $1 vai mõnõlõ |
| 492 | +[[{{MediaWiki:grouppage-sysop}}|tõõsõlõ kõrraldajalõ]]. |
| 493 | + |
| 494 | +Rehkendäq tuud, et sa saa-i tõisilõ pruukjilõ e-kirjo saataq, ku sa olõ-i ummi [[Special:Preferences|säädmiisihe]] kirjä pandnuq suq hindä masvat e-postiaadrõssit. |
| 495 | + |
| 496 | +Suq kinniqpidämise tunnusnummõr om $5. Olõq hää, kirodaq taa nummõr egä perräküsümise mano, miä sa tiit.", |
485 | 497 | 'blockedoriginalsource' => "Lehe '''$1''' lättekuud:", |
486 | 498 | 'blockededitsource' => "Su tett toimõndus lehe '''$1''' pääl:", |
487 | 499 | 'whitelistedittitle' => 'Toimõndamisõs piät nimega sisse minemä', |
— | — | @@ -744,6 +756,7 @@ |
745 | 757 | 'userrights-groupsmember' => 'Kuulus rühmä:', |
746 | 758 | 'userrights-groupsavailable' => 'Või mano pandaq rühmihe:', |
747 | 759 | 'userrights-groupshelp' => 'Valiq rühmäq, minkast sa tahat pruukjat ärq võttaq vai kohe mano pandaq. Valimalda jätetüid rühmi muudõda-i. Rühmä valimist saa tühäs tetäq CTRL + hüä hiirevaotusõga.', |
| 760 | +'userrights-reason' => 'Muutmisõ põhjus:', |
748 | 761 | |
749 | 762 | # Groups |
750 | 763 | 'group' => 'Rühm:', |
— | — | @@ -1129,14 +1142,17 @@ |
1130 | 1143 | 'watching' => 'Pandas perräkaemisnimekirjä...', |
1131 | 1144 | 'unwatching' => 'Võetas perräkaemisõ alt maaha...', |
1132 | 1145 | |
1133 | | -'enotif_mailer' => '{{SITENAME}} lehe muutumisteedüs', |
1134 | | -'enotif_reset' => 'Märgiq kõik leheq ülekaetuis', |
1135 | | -'enotif_newpagetext' => 'Taa om vahtsõnõ leht.', |
1136 | | -'changed' => 'lehte muutnuq', |
1137 | | -'created' => 'lehe loonuq', |
1138 | | -'enotif_subject' => '$PAGEEDITOR om $CHANGEDORCREATED $PAGETITLE', |
1139 | | -'enotif_lastvisited' => 'Lehel $1 ommaq kõik päält suq perämäst käümist tettüq muutmisõq.', |
1140 | | -'enotif_body' => 'Hüä $WATCHINGUSERNAME, |
| 1146 | +'enotif_mailer' => '{{SITENAME}} lehe muutumisteedüs', |
| 1147 | +'enotif_reset' => 'Märgiq kõik leheq ülekaetuis', |
| 1148 | +'enotif_newpagetext' => 'Taa om vahtsõnõ leht.', |
| 1149 | +'enotif_impersonal_salutation' => '{{SITENAME}} pruukja', |
| 1150 | +'changed' => 'lehte muutnuq', |
| 1151 | +'created' => 'lehe loonuq', |
| 1152 | +'enotif_subject' => '$PAGEEDITOR om $CHANGEDORCREATED $PAGETITLE', |
| 1153 | +'enotif_lastvisited' => 'Lehel $1 ommaq kõik päält suq perämäst käümist tettüq muutmisõq.', |
| 1154 | +'enotif_lastdiff' => 'Taa muutusõ nägemises kaeq: $1.', |
| 1155 | +'enotif_anon_editor' => 'nimeldä pruukja $1', |
| 1156 | +'enotif_body' => 'Hüä $WATCHINGUSERNAME, |
1141 | 1157 | |
1142 | 1158 | {{SITENAME}} lehte $PAGETITLE $CHANGEDORCREATED $PAGEEDITDATE $PAGEEDITOR, parhillast kujjo kaeq $PAGETITLE_URL. |
1143 | 1159 | |
— | — | @@ -1219,6 +1235,8 @@ |
1220 | 1236 | 'restriction-type' => 'Luba', |
1221 | 1237 | 'restriction-level' => 'Piirdmisastõq', |
1222 | 1238 | 'minimum-size' => 'Kõgõ vähämb maht (baidõn)', |
| 1239 | +'maximum-size' => 'Kõgõ suurõmb lubat suurus', |
| 1240 | +'pagesize' => '(baiti)', |
1223 | 1241 | |
1224 | 1242 | # Restrictions (nouns) |
1225 | 1243 | 'restriction-edit' => 'Toimõndus', |
— | — | @@ -1267,7 +1285,7 @@ |
1268 | 1286 | # Contributions |
1269 | 1287 | 'contributions' => 'Pruukja kirotusõq', |
1270 | 1288 | 'mycontris' => 'Mu kirotusõq', |
1271 | | -'contribsub2' => 'Pruukja "$1 ($2)" kirotusõq', |
| 1289 | +'contribsub2' => 'Pruukja "$1 ($2)" kirotusõq', |
1272 | 1290 | 'nocontribs' => 'Sääntsit muutmiisi es lövväq.', |
1273 | 1291 | 'ucnote' => 'Näüdätäseq taa pruukja tettüid <b>$1</b> viimäst muutmist viimädse <b>$2</b> päävä seen.', |
1274 | 1292 | 'uclinks' => 'Näütäq viimäst $1 muutmist; viimädse $2 päävä seen.', |
— | — | @@ -1306,6 +1324,15 @@ |
1307 | 1325 | 'ipadressorusername' => 'Puutri võrgoaadrõs vai pruukjanimi', |
1308 | 1326 | 'ipbexpiry' => 'Tähtaig', |
1309 | 1327 | 'ipbreason' => 'Põhjus', |
| 1328 | +'ipbreasonotherlist' => 'Muu põhjus', |
| 1329 | +'ipbreason-dropdown' => "*Hariliguq kinniqpidämise põhjusõq |
| 1330 | +** Võlss teedüse kirotaminõ |
| 1331 | +** Lehti sisu ärqkistutaminõ |
| 1332 | +** Reklaamilinkõ pandminõ |
| 1333 | +** Mõttõlda jutu vai prahi pandminõ |
| 1334 | +** Segämine ja ts'urkminõ |
| 1335 | +** Mitmõ pruukjanime võlsspruukminõ |
| 1336 | +** Sündümäldäq pruukjanimi", |
1310 | 1337 | 'ipbanononly' => 'Piäq kinniq õnnõ ilma nimeldä pruukjaq', |
1311 | 1338 | 'ipbcreateaccount' => 'Lasku-i pruukjanimme luvvaq', |
1312 | 1339 | 'ipbenableautoblock' => 'Piäq kinniq viimäne puutri võrgoaadrõs, kost pruukja om toimõnduisi tennüq, ja edespiten aadrõsiq, kost tä viil pruuv toimõnduisi tetäq.', |
— | — | @@ -1313,11 +1340,13 @@ |
1314 | 1341 | 'ipbother' => 'Muu tähtaig', |
1315 | 1342 | 'ipboptions' => '15 minotit:15 minutes,1 päiv:1 day,3 päivä:3 days,1 nätäl:1 week,2 nädälit:2 weeks,1 kuu:1 month,3 kuud:3 months,6 kuud:6 months,1 aastak:1 year,igävene:infinite', |
1316 | 1343 | 'ipbotheroption' => 'Muu tähtaig', |
| 1344 | +'ipbotherreason' => 'Muu põhjus', |
1317 | 1345 | 'ipbhidename' => 'Käkiq pruukjanimi vai puutri võrgoaadrõs ärq kinniqpidämis-, toimõndus-, ja pruukjanimekiräst', |
1318 | 1346 | 'badipaddress' => 'Puutri võrgoaadrõs om võlssi kirotõt.', |
1319 | 1347 | 'blockipsuccesssub' => 'Kinniqpidämine läts kõrda', |
1320 | 1348 | 'blockipsuccesstext' => 'Puutri võrgoaadrõs "$1" om kinniq peet. |
1321 | 1349 | <br />Kõik parhilladsõq kinniqpidämiseq lövvät [[Special:Ipblocklist|kinniqpidämiisi nimekiräst]].', |
| 1350 | +'ipb-edit-dropdown' => 'Toimõndaq kinniqpidämise põhjuisi', |
1322 | 1351 | 'ipb-unblock-addr' => 'Lõpõdaq pruukja $1 kinniqpidämine ärq', |
1323 | 1352 | 'ipb-unblock' => 'Lõpõdaq pruukja vai puutri võrgoaadrõasi kinniqpidämine ärq', |
1324 | 1353 | 'ipb-blocklist-addr' => 'Näütäq pruukja $1 kinniqpidämiisi', |
— | — | @@ -1326,6 +1355,7 @@ |
1327 | 1356 | 'unblockiptext' => 'Täüdäq ärq taa vorm, et lõpõtaq ärq pruukja vai puutri võrgoaadrõsi kinniqpidämine', |
1328 | 1357 | 'ipusubmit' => 'Lõpõdaq kinniqpidämine ärq', |
1329 | 1358 | 'unblocked' => 'Pruukja [[User:$1|$1]] kinniqpidämine om ärq lõpõtõt', |
| 1359 | +'unblocked-id' => '$1 kinniqpidämine võeti maaha', |
1330 | 1360 | 'ipblocklist' => 'Kinniqpeetüisi IP-aadrõssidõ nimekiri', |
1331 | 1361 | 'ipblocklist-submit' => 'Otsiq', |
1332 | 1362 | 'blocklistline' => '$1 — $2 om kinniq pidänüq pruukja $3 ($4)', |
— | — | @@ -1334,7 +1364,8 @@ |
1335 | 1365 | 'anononlyblock' => 'õnnõ nimeldä pruukjaq', |
1336 | 1366 | 'noautoblockblock' => 'automaatsõ kinniqpidämiseldä', |
1337 | 1367 | 'createaccountblock' => 'pruukjanime luuminõ kinniq pant', |
1338 | | -'ipblocklistempty' => 'Kinniqpidämiisi nimekiri om tühi (vai olõ-i otsitut aadrõssit vai pruukjanimme kinniq peet).', |
| 1368 | +'ipblocklist-empty' => 'Kinniqpidämiisi nimekiri om tühi.', |
| 1369 | +'ipblocklist-no-results' => 'Taa puutri võrgoaadrõss vai pruukjanimi olõ-i kinniq peet.', |
1339 | 1370 | 'blocklink' => 'piäq kinniq', |
1340 | 1371 | 'unblocklink' => 'võtaq kinniqpidämine maaha', |
1341 | 1372 | 'contribslink' => 'kirotusõq', |
— | — | @@ -1517,6 +1548,8 @@ |
1518 | 1549 | 'tooltip-t-emailuser' => 'Saadaq taalõ pruukjalõ e-kiri', |
1519 | 1550 | 'tooltip-t-upload' => 'Panõq mano pilte vai meediäteedüstüid', |
1520 | 1551 | 'tooltip-t-specialpages' => 'Näütäq tallituslehekülgi', |
| 1552 | +'tooltip-t-print' => 'Taa lehe trükükujo', |
| 1553 | +'tooltip-t-permalink' => 'Seo lehekujo püsülink', |
1521 | 1554 | 'tooltip-ca-nstab-main' => 'Näütäq sisulehekülge', |
1522 | 1555 | 'tooltip-ca-nstab-user' => 'Näütäq pruukjalehekülge', |
1523 | 1556 | 'tooltip-ca-nstab-media' => 'Näütäq meediälehekülge', |
— | — | @@ -2018,6 +2051,10 @@ |
2019 | 2052 | 'livepreview-error' => 'Ütistämine lää-s kõrda: $1 "$2" |
2020 | 2053 | Prooviq harilikku kaehust.', |
2021 | 2054 | |
| 2055 | +# Friendlier slave lag warnings |
| 2056 | +'lag-warn-normal' => 'Muutmiisi, miä ommaq vahtsõmbaq ku $1 sekundit, pruugi-i taan nimekirän nätäq ollaq.', |
| 2057 | +'lag-warn-high' => 'Teedüskogoserveri aiglusõ peräst pruugi-i $1 sekundist värskimbit muutmiisi nimekirän nätäq ollaq.', |
| 2058 | + |
2022 | 2059 | ); |
2023 | 2060 | |
2024 | 2061 | ?> |
Index: branches/liquidthreads/languages/messages/MessagesKk_cn.php |
— | — | @@ -174,7 +174,7 @@ |
175 | 175 | 'localmonth' => array( 1, 'جەرگٸلٸكتٸاي', 'LOCALMONTH' ), |
176 | 176 | 'localmonthname' => array( 1, 'جەرگٸلٸكتٸاياتاۋى', 'LOCALMONTHNAME' ), |
177 | 177 | 'localmonthnamegen' => array( 1, 'جەرگٸلٸكتٸايٸلٸكاتاۋى', 'LOCALMONTHNAMEGEN' ), |
178 | | - 'localmonthabbrev' => array( 1, 'جەرگٸلٸكتٸايجيىر', 'جەرگٸلٸكتٸايقىسقا', 'LOCALMONTHABBREV' ), |
| 178 | + 'localmonthabbrev' => array( 1, 'جەرگٸلٸكتٸايجيىر', 'جەرگٸلٸكتٸايقىسقاشا', 'جەرگٸلٸكتٸايقىسقا', 'LOCALMONTHABBREV' ), |
179 | 179 | 'localday' => array( 1, 'جەرگٸلٸكتٸكٷن', 'LOCALDAY' ), |
180 | 180 | 'localday2' => array( 1, 'جەرگٸلٸكتٸكٷن2', 'LOCALDAY2' ), |
181 | 181 | 'localdayname' => array( 1, 'جەرگٸلٸكتٸكٷناتاۋى', 'LOCALDAYNAME' ), |
— | — | @@ -196,8 +196,8 @@ |
197 | 197 | 'subjectspacee' => array( 1, 'تاقىرىپبەتٸ2', 'ماقالابەتٸ2', 'SUBJECTSPACEE', 'ARTICLESPACEE' ), |
198 | 198 | 'fullpagename' => array( 1, 'تولىقبەتاتاۋى', 'FULLPAGENAME' ), |
199 | 199 | 'fullpagenamee' => array( 1, 'تولىقبەتاتاۋى2', 'FULLPAGENAMEE' ), |
200 | | - 'subpagename' => array( 1, 'استىڭعىبەتاتاۋى', 'SUBPAGENAME' ), |
201 | | - 'subpagenamee' => array( 1, 'استىڭعىبەتاتاۋى2', 'SUBPAGENAMEE' ), |
| 200 | + 'subpagename' => array( 1, 'بەتشەاتاۋى', 'استىڭعىبەتاتاۋى', 'SUBPAGENAME' ), |
| 201 | + 'subpagenamee' => array( 1, 'بەتشەاتاۋى2', 'استىڭعىبەتاتاۋى2', 'SUBPAGENAMEE' ), |
202 | 202 | 'basepagename' => array( 1, 'نەگٸزگٸبەتاتاۋى', 'BASEPAGENAME' ), |
203 | 203 | 'basepagenamee' => array( 1, 'نەگٸزگٸبەتاتاۋى2', 'BASEPAGENAMEE' ), |
204 | 204 | 'talkpagename' => array( 1, 'تالقىلاۋبەتاتاۋى', 'TALKPAGENAME' ), |
— | — | @@ -215,6 +215,7 @@ |
216 | 216 | 'img_width' => array( 1, '$1 px', '$1px' ), |
217 | 217 | 'img_center' => array( 1, 'ورتاعا', 'ورتا', 'center', 'centre' ), |
218 | 218 | 'img_framed' => array( 1, 'سٷرمەلٸ', 'framed', 'enframed', 'frame' ), |
| 219 | + 'img_frameless' => array( 1, 'سٷرمەسٸز', 'frameless' ), |
219 | 220 | 'img_page' => array( 1, 'بەت=$1', 'بەت $1', 'page=$1', 'page $1' ), |
220 | 221 | 'img_upright' => array( 1, 'تٸكتٸ', 'تٸكتٸك=$1', 'تٸكتٸك $1' ), |
221 | 222 | 'img_border' => array( 1, 'شەكتٸ' ), |
— | — | @@ -228,18 +229,18 @@ |
229 | 230 | 'img_text-bottom' => array( 1, 'مٵتٸن-استىندا', 'text-bottom' ), |
230 | 231 | 'int' => array( 0, 'ٸشكٸ:', 'INT:' ), |
231 | 232 | 'sitename' => array( 1, 'توراپاتاۋى', 'SITENAME' ), |
232 | | - 'ns' => array( 0, 'ەا:', 'NS:' ), |
| 233 | + 'ns' => array( 0, 'ەا:', 'ەسٸمايا:', 'NS:' ), |
233 | 234 | 'localurl' => array( 0, 'جەرگٸلٸكتٸجاي:', 'LOCALURL:' ), |
234 | 235 | 'localurle' => array( 0, 'جەرگٸلٸكتٸجاي2:', 'LOCALURLE:' ), |
235 | 236 | 'server' => array( 0, 'سەرۆەر', 'SERVER' ), |
236 | 237 | 'servername' => array( 0, 'سەرۆەراتاۋى', 'SERVERNAME' ), |
237 | 238 | 'scriptpath' => array( 0, 'ٵمٸرجولى', 'SCRIPTPATH' ), |
238 | | - 'grammar' => array( 0, 'سەپتٸك:', 'GRAMMAR:' ), |
| 239 | + 'grammar' => array( 0, 'سەپتٸگٸ:', 'سەپتٸك:', 'GRAMMAR:' ), |
239 | 240 | 'notitleconvert' => array( 0, '__اتاۋالماستىرعىزباۋ__', '__ااباۋ__', '__NOTITLECONVERT__', '__NOTC__' ), |
240 | 241 | 'nocontentconvert' => array( 0, '__ماعلۇماتالماستىرعىزباۋ__', '__ماباۋ__', '__NOCONTENTCONVERT__', '__NOCC__' ), |
241 | | - 'currentweek' => array( 1, 'اعىمداعىاپتا', 'CURRENTWEEK' ), |
| 242 | + 'currentweek' => array( 1, 'اعىمداعىاپتاسى', 'اعىمداعىاپتا', 'CURRENTWEEK' ), |
242 | 243 | 'currentdow' => array( 1, 'اعىمداعىاپتاكٷنٸ', 'CURRENTDOW' ), |
243 | | - 'localweek' => array( 1, 'جەرگٸلٸكتٸاپتا', 'LOCALWEEK' ), |
| 244 | + 'localweek' => array( 1, 'جەرگٸلٸكتٸاپتاسى', 'جەرگٸلٸكتٸاپتا', 'LOCALWEEK' ), |
244 | 245 | 'localdow' => array( 1, 'جەرگٸلٸكتٸاپتاكٷنٸ', 'LOCALDOW' ), |
245 | 246 | 'revisionid' => array( 1, 'نۇسقانٶمٸرٸ', 'REVISIONID' ), |
246 | 247 | 'revisionday' => array( 1, 'نۇسقاكٷنٸ' , 'REVISIONDAY' ), |
— | — | @@ -247,13 +248,13 @@ |
248 | 249 | 'revisionmonth' => array( 1, 'نۇسقاايى', 'REVISIONMONTH' ), |
249 | 250 | 'revisionyear' => array( 1, 'نۇسقاجىلى', 'REVISIONYEAR' ), |
250 | 251 | 'revisiontimestamp' => array( 1, 'نۇسقاۋاقىتتٷيٸندەمەسٸ', 'REVISIONTIMESTAMP' ), |
251 | | - 'plural' => array( 0, 'كٶپشە:', 'PLURAL:' ), |
252 | | - 'fullurl' => array( 0, 'تولىقجاي:', 'FULLURL:' ), |
253 | | - 'fullurle' => array( 0, 'تولىقجاي2:', 'FULLURLE:' ), |
254 | | - 'lcfirst' => array( 0, 'كٵ1:', 'LCFIRST:' ), |
255 | | - 'ucfirst' => array( 0, 'بٵ1:', 'UCFIRST:' ), |
256 | | - 'lc' => array( 0, 'كٵ:', 'LC:' ), |
257 | | - 'uc' => array( 0, 'بٵ:', 'UC:' ), |
| 252 | + 'plural' => array( 0, 'كٶپشەتٷرٸ:','كٶپشە:', 'PLURAL:' ), |
| 253 | + 'fullurl' => array( 0, 'تولىقجايى:', 'تولىقجاي:', 'FULLURL:' ), |
| 254 | + 'fullurle' => array( 0, 'تولىقجايى2:', 'تولىقجاي2:', 'FULLURLE:' ), |
| 255 | + 'lcfirst' => array( 0, 'كٵ1:', 'كٸشٸٵرٸپپەن1:', 'LCFIRST:' ), |
| 256 | + 'ucfirst' => array( 0, 'بٵ1:', 'باسٵرٸپپەن1:', 'UCFIRST:' ), |
| 257 | + 'lc' => array( 0, 'كٵ:', 'كٸشٸٵرٸپپەن:', 'LC:' ), |
| 258 | + 'uc' => array( 0, 'بٵ:', 'باسٵرٸپپەن:', 'UC:' ), |
258 | 259 | 'raw' => array( 0, 'قام:', 'RAW:' ), |
259 | 260 | 'displaytitle' => array( 1, 'كٶرسەتٸلەتٸناتاۋ', 'DISPLAYTITLE' ), |
260 | 261 | 'rawsuffix' => array( 1, 'ق', 'R' ), |
— | — | @@ -269,8 +270,8 @@ |
270 | 271 | 'pagesinnamespace' => array( 1, 'ەسٸمايابەتسانى:', 'ەابەتسانى:', 'ايابەتسانى:', 'PAGESINNAMESPACE:', 'PAGESINNS:' ), |
271 | 272 | 'numberofadmins' => array( 1, 'ٵكٸمشٸسانى', 'NUMBEROFADMINS' ), |
272 | 273 | 'formatnum' => array( 0, 'سانپٸشٸمٸ', 'FORMATNUM' ), |
273 | | - 'padleft' => array( 0, 'سولىعىس', 'PADLEFT' ), |
274 | | - 'padright' => array( 0, 'وڭىعىس', 'PADRIGHT' ), |
| 274 | + 'padleft' => array( 0, 'سولعاىعىس', 'سولىعىس', 'PADLEFT' ), |
| 275 | + 'padright' => array( 0, 'وڭعاىعىس', 'وڭىعىس', 'PADRIGHT' ), |
275 | 276 | 'special' => array( 0, 'ارنايى', 'special', ), |
276 | 277 | 'defaultsort' => array( 1, 'ٵدەپكٸسۇرىپتاۋ:', 'ٵدەپكٸسۇرىپ:', 'DEFAULTSORT:' ), |
277 | 278 | ); |
— | — | @@ -355,7 +356,7 @@ |
356 | 357 | $messages = array( |
357 | 358 | # User preference toggles |
358 | 359 | 'tog-underline' => 'سٸلتەمەنٸ استىنان سىز:', |
359 | | -'tog-highlightbroken' => 'جوقتالعان سٸلتەمەلەردٸ <a href="" class="new">بىلاي</a> پٸشٸمدە (باسقاشا: بىلاي <a href="" class="internal">؟</a> سيياقتى).', |
| 360 | +'tog-highlightbroken' => 'جارامسىز سٸلتەمەلەردٸ <a href="" class="new">بىلاي</a> پٸشٸمدە (بالاماسى: بىلاي <a href="" class="internal">؟</a> سيياقتى).', |
360 | 361 | 'tog-justify' => 'ەجەلەردٸ ەنٸ بويىنشا تۋرالاۋ', |
361 | 362 | 'tog-hideminor' => 'جۋىقتاعى ٶزگەرٸستەردە شاعىن تٷزەتۋدٸ جاسىر', |
362 | 363 | 'tog-extendwatchlist' => 'باقىلاۋ تٸزٸمدٸ ۇلعايت (بارلىق جارامدى ٶزگەرٸستەردٸ كٶرسەت)', |
— | — | @@ -456,7 +457,7 @@ |
457 | 458 | 'categories' => 'بارلىق سانات تٸزٸمٸ', |
458 | 459 | 'pagecategories' => '{{PLURAL:$1|سانات|ساناتتار}}', |
459 | 460 | 'category_header' => '«$1» ساناتىنداعى بەتتەر', |
460 | | -'subcategories' => 'تٶمەنگٸ ساناتتار', |
| 461 | +'subcategories' => 'ساناتشالار', |
461 | 462 | 'category-media-header' => '«$1» ساناتىنداعى تاسپالار', |
462 | 463 | |
463 | 464 | 'linkprefix' => '/^(.*?)([a-zäçéğıïñöşüýа-яёәіңғүұқөһA-ZÄÇÉĞİÏÑÖŞÜÝА-ЯЁӘІҢҒҮҰҚӨҺʺʹ«„]+)$/sDu', |
— | — | @@ -895,7 +896,7 @@ |
896 | 897 | 'nonunicodebrowser' => '<strong>اڭعارتپا: شولعىشىڭىز Unicode بەلگٸلەۋٸنە ٷيلەسٸمدٸ ەمەس, سوندىقتان لاتىن ەمەس ٵرٸپتەرٸ بار بەتتەردٸ ٶڭدەۋ زٸل بولۋ مٷمكٸن. جۇمىس ٸستەۋگە ىقتيمالدىق بەرۋ ٷشٸن, تٶمەنگٸ ٶڭدەۋ اۋماعىندا ASCII ەمەس ٵرٸپتەر ونالتىلىق سانىمەن كٶرسەتٸلەدٸ</strong>.', |
897 | 898 | 'editingold' => '<strong>اڭعارتپا: وسى بەتتٸڭ ەرتەرەك نۇسقاسىن |
898 | 899 | ٶڭدەپ جاتىرسىز. |
899 | | -بۇنى ساقتاساڭىز, وسى نۋسقادان سوڭعى بارلىق تٷزەتۋلەر جويىلادى.</strong>', |
| 900 | +بۇنى ساقتاساڭىز, وسى نۋسقادان سوڭعى بارلىق ٶزگەرٸستەر جويىلادى.</strong>', |
900 | 901 | 'yourdiff' => 'ايىرمالار', |
901 | 902 | 'copyrightwarning' => '{{SITENAME}} جوباسىنا قوسىلعان بٷكٸل ٷلەس $2 (كٶبٸرەك اقپارات ٷشٸن: $1) قۇجاتىنا ساي جٸبەرٸلگەن بولىپ سانالادى. ەگەر جازۋىڭىزدىڭ ەركٸن كٶشٸرٸلٸپ تٷزەتٸلۋٸن قالاماساڭىز, مىندا ۇسىنباۋىڭىز جٶن.<br /> |
902 | 903 | تاعى, قوسقان ٷلەسٸڭٸز - ٶزٸڭٸزدٸڭ جازعانىعىز, نە اشىق اقپارات كٶزدەرٸنەن الىنعان ماعلۇمات بولعانىن ۋٵدە ەتەسٸز.<br /> |
— | — | @@ -1076,7 +1077,7 @@ |
1077 | 1078 | 'qbsettings-fixedright' => 'وڭعا بەكٸتٸلگەن', |
1078 | 1079 | 'qbsettings-floatingleft' => 'سولعا قالقىعان', |
1079 | 1080 | 'qbsettings-floatingright' => 'وڭعا قالقىعان', |
1080 | | -'changepassword' => 'قۇپييا سٶز ٶزگەرتۋ', |
| 1081 | +'changepassword' => 'قۇپييا سٶزدٸ اۋىستىرۋ', |
1081 | 1082 | 'skin' => 'بەزەندٸرۋ', |
1082 | 1083 | 'math' => 'ماتەماتيكا', |
1083 | 1084 | 'dateformat' => 'كٷن-اي پٸشٸمٸ', |
— | — | @@ -1158,7 +1159,7 @@ |
1159 | 1160 | 'rightsnone' => '(ەشقانداي)', |
1160 | 1161 | |
1161 | 1162 | # Recent changes |
1162 | | -'nchanges' => '{{PLURAL:$1|بٸر تٷزەتۋ|$1 تٷزەتۋ}}', |
| 1163 | +'nchanges' => '{{PLURAL:$1|بٸر ٶزگەرٸس|$1 ٶزگەرٸس}}', |
1163 | 1164 | 'recentchanges' => 'جۋىقتاعى ٶزگەرٸستەر', |
1164 | 1165 | 'recentchangestext' => 'بۇل بەتتە وسى ۋيكيدەگٸ بولعان جۋىقتاعى ٶزگەرٸستەر بايقالادى.', |
1165 | 1166 | 'recentchanges-feed-description' => 'بۇل ارنامەنەن ۋيكيدەگٸ ەڭ سوڭعى ٶزگەرٸستەر قاداعالانادى.', |
— | — | @@ -1185,9 +1186,9 @@ |
1186 | 1187 | 'rc_categories_any' => 'قايسىبٸر', |
1187 | 1188 | |
1188 | 1189 | # Recent changes linked |
1189 | | -'recentchangeslinked' => 'قاتىستى تٷزەتۋلەر', |
| 1190 | +'recentchangeslinked' => 'قاتىستى ٶزگەرٸستەر', |
1190 | 1191 | 'recentchangeslinked-noresult' => 'سٸلتەگەن بەتتەردە ايتىلمىش مەرزٸمدە ەشقانداي ٶزگەرٸس بولماعان.', |
1191 | | -'recentchangeslinked-summary' => "بۇل ارنايى بەتتە سٸلتەگەن بەتتەردەگٸ جۋىقتاعى ٶزگەرٸستەر تٸزٸمٸ بەرٸلەدٸ. باقىلاۋ تٸزٸمٸڭٸزدەگٸ بەتتەر '''جۋان''' ٵرپٸمەن بەلگٸلەنەدٸ.", |
| 1192 | +'recentchangeslinked-summary' => "بۇل ارنايى بەتتە سٸلتەگەن بەتتەردەگٸ جۋىقتاعى ٶزگەرٸستەر تٸزٸمٸ بەرٸلەدٸ. باقىلاۋ تٸزٸمٸڭٸزدەگٸ بەتتەر '''جۋان''' ٵربٸمەن بەلگٸلەنەدٸ.", |
1192 | 1193 | |
1193 | 1194 | # Upload |
1194 | 1195 | 'upload' => 'فايل قوتارۋ', |
— | — | @@ -1225,8 +1226,8 @@ |
1226 | 1227 | 'filetype-missing' => 'بۇل فايلدىڭ («.jpg» سيياقتى) كەڭەيتٸمٸ جوق.', |
1227 | 1228 | 'large-file' => 'فايلدى $1 مٶلشەردەن اسپاۋىنا تىرىسىڭىز; بۇل فايل مٶلشەرٸ — $2.', |
1228 | 1229 | 'largefileserver' => 'وسى فايلدىڭ مٶلشەرٸ سەرۆەردٸڭ قالاۋىنان اسىپ كەتكەن.', |
1229 | | -'emptyfile' => 'قوتارىلعان فايلىڭىز بوس سيياقتى. بۇل فايل اتاۋى جانساق ەنگٸزٸلگەنٸنەن بولۋى مٷمكٸن. قوتارعىڭىز كەلگەن فايل شىنىندا دا وسى فايل بولعانىن تەكسەرٸپ الىڭىز.', |
1230 | | -'fileexists' => 'وسىنداي اتاۋلى فايل بار تٷگە. قايتا جازۋدىڭ الدىنان $1 تەكسەرٸپ شىعىڭىز.', |
| 1230 | +'emptyfile' => 'قوتارىلعان فايلىڭىز بوس سيياقتى. بۇل فايل اتاۋىندا قاتە بولۋى مٷمكٸن. وسى فايلدى شىنايى قوتارعىڭىز كەلەتٸن تەكسەرٸپ شىعىڭىز.', |
| 1231 | +'fileexists' => 'وسىنداي اتاۋلى فايل بار تٷگە, ەگەر بۇنى ٶزگەرتۋگە سەنٸمٸڭٸز جوق بولسا <strong><tt>$1</tt></strong> دەگەندٸ تەكسەرٸپ شىعىڭىز.', |
1231 | 1232 | 'fileexists-extension' => 'ۇقساستى فايل اتاۋى بار تٷگە:<br /> |
1232 | 1233 | قوتارىلاتىن فايل اتاۋى: <strong><tt>$1</tt></strong><br /> |
1233 | 1234 | بار بولعان فايل اتاۋى: <strong><tt>$2</tt></strong><br /> |
— | — | @@ -1313,7 +1314,7 @@ |
1314 | 1315 | |
1315 | 1316 | # MIME search |
1316 | 1317 | 'mimesearch' => 'فايلدى MIME تٷرٸمەن ٸزدەۋ', |
1317 | | -'mimesearch-summary' => 'بۇل بەت فايلداردى MIME تٷرٸمەن سٷزگٸلەۋ مٷمكٸندٸگٸن بەرەدٸ. كٸرٸسٸ: «ماعلۇمات تٷرٸ»/«تاراۋ تٷرٸ», مىسالى <tt>image/jpeg</tt>.', |
| 1318 | +'mimesearch-summary' => 'بۇل بەت فايلداردى MIME تٷرٸمەن سٷزگٸلەۋ مٷمكٸندٸگٸن بەرەدٸ. كٸرٸسٸ: «ماعلۇمات تٷرٸ»/«تٷر تاراۋى», مىسالى <tt>image/jpeg</tt>.', |
1318 | 1319 | 'mimetype' => 'MIME تٷرٸ:', |
1319 | 1320 | 'download' => 'جٷكتەۋ', |
1320 | 1321 | |
— | — | @@ -1351,7 +1352,7 @@ |
1352 | 1353 | |
1353 | 1354 | اعىمدىق [http://meta.wikimedia.org/wiki/Help:Job_queue تاپسىرىم كەزەگٸ] ۇزىندىلىعى: '''$7'''.", |
1354 | 1355 | 'userstatstext' => "مىندا {{PLURAL:$1|'''1''' تٸركەلگەن قاتىسۋشى|'''$1''' تٸركەلگەن قاتىسۋشى}} بار, سونىڭ ٸشٸندە |
1355 | | - {{PLURAL:$2|'''1''' قاتىسۋشىدا|'''$2''' قاتىسۋشىدا}} (نەمەسە '''$4 ٪''') $5 قۇقىقتارى بار", |
| 1356 | + {{PLURAL:$2|'''1''' قاتىسۋشىدا|'''$2''' قاتىسۋشىدا}} (نەمەسە '''$4 %''') $5 قۇقىقتارى بار", |
1356 | 1357 | 'statistics-mostpopular' => 'ەڭ كٶپ قارالعان بەتتەر', |
1357 | 1358 | |
1358 | 1359 | 'disambiguations' => 'ايرىقتى بەتتەر', |
— | — | @@ -1527,7 +1528,7 @@ |
1528 | 1529 | * [[{{ns:special}}:Watchlist/edit|بٷكٸل تٸزٸمدٸ قاراۋ جٵنە ٶزگەرتۋ]]. |
1529 | 1530 | * [[{{ns:special}}:Watchlist/clear|تٸزٸمدەگٸ بارلىق دانا الاستاتۋ]].", |
1530 | 1531 | 'wlheader-enotif' => '* ەسكەرتۋ حات جٸبەرۋٸ ەندٸرٸلگەن.', |
1531 | | -'wlheader-showupdated' => "* سوڭعى كٸرگەنٸمنەن بەرٸ تٷزەتٸلگەن بەتتەردٸ '''جۋان''' مٵتٸنمەن كٶرسەت", |
| 1532 | +'wlheader-showupdated' => "* سوڭعى كٸرگەنٸمنەن بەرٸ ٶزگەرتٸلگەن بەتتەردٸ '''جۋان''' ٵربٸمەن كٶرسەت", |
1532 | 1533 | 'watchmethod-recent' => 'باقىلاۋلى بەتتەردٸڭ جۋىقتاعى ٶزگەرٸستەرٸن تەكسەرۋ', |
1533 | 1534 | 'watchmethod-list' => 'جۋىقتاعى ٶزگەرٸستەردە باقىلاۋلى بەتتەردٸ تەكسەرۋ', |
1534 | 1535 | 'removechecked' => 'بەلگٸلەنگەندٸ باقىلاۋ تٸزٸمٸنەن الاستاتۋ', |
— | — | @@ -1628,7 +1629,7 @@ |
1629 | 1630 | «ارتقا» تٷيمەسٸن باسىڭىز, جٵنە بەتتٸ كەرٸ جٷكتەڭٸز, سوسىن قايتالاپ كٶرٸڭٸز.', |
1630 | 1631 | 'protectlogpage' => 'قورعاۋ_جۋرنالى', |
1631 | 1632 | 'protectlogtext' => 'تٶمەندە بەتتەردٸڭ قورعاۋ/قورعاماۋ تٸزٸمٸ بەرٸلگەن. اعىمداعى قورعاۋ ٵرەكتتەر بار بەتتەر ٷشٸن [[{{ns:special}}:Protectedpages|قورعالعان بەت تٸزٸمٸن]] قاراڭىز.', |
1632 | | -'protectedarticle' => '«$1» قورعالدى', |
| 1633 | +'protectedarticle' => '«[[$1]]» قورعالدى', |
1633 | 1634 | 'unprotectedarticle' => '«[[$1]]» قورعالمادى', |
1634 | 1635 | 'protectsub' => '(«$1» قورعاۋدا)', |
1635 | 1636 | 'confirmprotecttext' => 'وسى بەتتٸ راسىندا دا قورعاۋ قاجەت پە؟', |
— | — | @@ -1658,7 +1659,7 @@ |
1659 | 1660 | 'protect-expiring' => 'بٸتۋٸ: $1 (UTC)', |
1660 | 1661 | 'protect-cascade' => 'باۋلى قورعاۋ — بۇل بەتكە كٸرٸستٸرٸلگەن ٵرقايسى بەتتەردٸ قورعاۋ.', |
1661 | 1662 | 'restriction-type' => 'رۇقساتى:', |
1662 | | -'restriction-level' => 'رۇقسات دەڭگەيٸ:', |
| 1663 | +'restriction-level' => 'رۇقسات شەكتەۋ دەڭگەيٸ:', |
1663 | 1664 | 'minimum-size' => 'ەڭ از مٶلشەرٸ', |
1664 | 1665 | 'maximum-size' => 'ەڭ كٶپ مٶلشەرٸ', |
1665 | 1666 | 'pagesize' => '(بايت)', |
— | — | @@ -1702,7 +1703,7 @@ |
1703 | 1704 | 'undeletedarticle' => '«[[$1]]» قايتاردى', |
1704 | 1705 | 'undeletedrevisions' => '{{PLURAL:$1|نۇسقانى|$1 نۇسقانى}} قايتاردى', |
1705 | 1706 | 'undeletedrevisions-files' => '{{PLURAL:$1|نۇسقانى|$1 نۇسقانى}} جٵنە {{PLURAL:$2|فايلدى|$2 فايلدى}} قايتاردى', |
1706 | | -'undeletedfiles' => '{{PLURAL:$1|1 فايل|$1 فايل}} قايتاردى', |
| 1707 | +'undeletedfiles' => '{{PLURAL:$1|1 فايلدى|$1 فايلدى}} قايتاردى', |
1707 | 1708 | 'cannotundelete' => 'قايتارۋ سٵتسٸز بٸتتٸ; تاعى بٸرەۋ سٸزدەن بۇرىن سول بەتتٸ قايتارعان بولار.', |
1708 | 1709 | 'undeletedpage' => "<big>'''$1 قايتارىلدى'''</big> |
1709 | 1710 | |
— | — | @@ -1722,8 +1723,8 @@ |
1723 | 1724 | 'mycontris' => 'ٷلەسٸم', |
1724 | 1725 | 'contribsub2' => '$1 ($2) ٷلەسٸ', |
1725 | 1726 | 'nocontribs' => 'وسى ٸزدەۋ شارتىنا سٵيكەس ٶزگەرٸستەر تابىلعان جوق.', |
1726 | | -'ucnote' => 'تٶمەندە وسى قاتىسۋشىنىڭ سوڭعى <b>$2</b> كٷندەگٸ, سوڭعى <b>$1</b> ٶزگەرٸسٸ كٶرسەتلەدٸ.', |
1727 | | -'uclinks' => 'سوڭعى $2 كٷندەگٸ, سوڭعى $1 ٶزگەرٸسٸن قاراۋ.', |
| 1727 | +'ucnote' => 'تٶمەندە وسى قاتىسۋشى جاساعان سوڭعى <b>$2</b> كٷندەگٸ, سوڭعى <b>$1</b> ٶزگەرٸسٸ كٶرسەتلەدٸ.', |
| 1728 | +'uclinks' => 'سوڭعى $2 كٷندەگٸ, سوڭعى جاسالعان $1 ٶزگەرٸسٸن قاراۋ.', |
1728 | 1729 | 'uctop' => ' (ٷستٸ)', |
1729 | 1730 | |
1730 | 1731 | 'sp-contributions-newest' => 'ەڭ جاڭاسىنا', |
— | — | @@ -1753,6 +1754,7 @@ |
1754 | 1755 | 'istemplate' => 'كٸرٸكتٸرۋ', |
1755 | 1756 | 'whatlinkshere-prev' => '{{PLURAL:$1|الدىڭعى|الدىڭعى $1}}', |
1756 | 1757 | 'whatlinkshere-next' => '{{PLURAL:$1|كەلەسٸ|كەلەسٸ $1}}', |
| 1758 | +'whatlinkshere-links' => '← سٸلتەمەلەر', |
1757 | 1759 | |
1758 | 1760 | # Block/unblock |
1759 | 1761 | 'blockip' => 'پايدالانۋشىنى بۇعاتتاۋ', |
— | — | @@ -1873,7 +1875,7 @@ |
1874 | 1876 | بارلىق تاريحىن جاڭا اتاۋعا جىلجىتادى. |
1875 | 1877 | بۇرىنعى بەت اتاۋى جاڭا اتاۋعا ايداتاتىن بەت بولادى. |
1876 | 1878 | ەسكٸ اتاۋىنا سٸلتەيتٸن سٸلتەمەلەر ٶزگەرتٸلمەيدٸ; جىلجىتۋدان سوڭ |
1877 | | -شىنجىرلى ايداتۋلار بار-جوعىن تەكسەرٸڭٸز. |
| 1879 | +شىنجىرلى نە جارامسىز ايداتۋلار بار-جوعىن تەكسەرٸپ شىعىڭىز. |
1878 | 1880 | سٸلتەمەلەر بۇرىنعى جولداۋىمەن بىلايعى ٶتۋٸن تەكسەرۋٸنە |
1879 | 1881 | سٸز مٸندەتتٸ بولاسىز. |
1880 | 1882 | |
— | — | @@ -1884,7 +1886,7 @@ |
1885 | 1887 | بٸراق بار بەتتٸڭ ٷستٸنە جازۋعا بولمايدى. |
1886 | 1888 | |
1887 | 1889 | <b>نازار سالىڭىز!</b> |
1888 | | -بۇل دٵرٸپتٸ بەتكە قاتاڭ جٵنە كەنەت ٶزگەرٸس جاساۋعا مٷمكٸن; |
| 1890 | +بۇل ٵيگٸلٸ بەتكە قاتاڭ جٵنە كەنەت ٶزگەرٸس جاساۋعا مٷمكٸن; |
1889 | 1891 | ٵرەكەتتٸڭ الدىنان وسىنىڭ زارداپتارىن تٷسٸنگەنٸڭٸزگە باتىل |
1890 | 1892 | بولىڭىز.", |
1891 | 1893 | 'movepagetalktext' => "كەلەسٸ سەبەپتەر '''بولعانشا''' دەيٸن, تالقىلاۋ بەتٸ ٶزدٸكتٸك بٸرگە جىلجىتىلادى: |
— | — | @@ -2049,8 +2051,8 @@ |
2050 | 2052 | 'tooltip-ca-nstab-help' => 'انىقتىما بەتٸن قاراۋ', |
2051 | 2053 | 'tooltip-ca-nstab-category' => 'سانات بەتٸن قاراۋ', |
2052 | 2054 | 'tooltip-minoredit' => 'وسىنى شاعىن تٷزەتۋ دەپ بەلگٸلەۋ', |
2053 | | -'tooltip-save' => 'تٷزەتۋٸڭٸزدٸ ساقتاۋ', |
2054 | | -'tooltip-preview' => 'ساقتاۋدىڭ الدىنان تٷزەتۋٸڭٸزدٸ قاراپ شىعىڭىز!', |
| 2055 | +'tooltip-save' => 'جاساعان ٶزگەرٸستەرٸڭٸزدٸ ساقتاۋ', |
| 2056 | +'tooltip-preview' => 'ساقتاۋدىڭ الدىنان جاساعان ٶزگەرٸستەرٸڭٸزدٸ قاراپ شىعىڭىز!', |
2055 | 2057 | 'tooltip-diff' => 'مٵتٸنگە قانداي ٶزگەرٸستەردٸ جاساعانىڭىزدى قاراۋ.', |
2056 | 2058 | 'tooltip-compareselectedversions' => 'بەتتٸڭ ەكٸ نۇسقاسىنىڭ ايىرماسىن قاراۋ.', |
2057 | 2059 | 'tooltip-watch' => 'بۇل بەتتٸ باقىلاۋ تٸزٸمٸڭٸزگە ٷستەۋ', |
— | — | @@ -2142,7 +2144,7 @@ |
2143 | 2145 | 'spamprotectiontitle' => '«سپام»-نان قورعايتىن سٷزگٸ', |
2144 | 2146 | 'spamprotectiontext' => 'بۇل بەتتٸڭ ساقتاۋىن «سپام» سٷزگٸسٸ بۇعاتتادى. بۇنىڭ سەبەبٸ سىرتقى توراپ سٸلتەمەسٸنەن بولۋى مٷمكٸن.', |
2145 | 2147 | 'spamprotectionmatch' => 'كەلەسٸ «سپام» مٵتٸنٸ سٷزگٸلەنگەن: $1', |
2146 | | -'subcategorycount' => 'بۇل ساناتتا {{PLURAL:$1|بٸر|$1}} تٶمەنگٸ سانات بار.', |
| 2148 | +'subcategorycount' => 'بۇل ساناتتا {{PLURAL:$1|بٸر|$1}} ساناتشا بار.', |
2147 | 2149 | 'categoryarticlecount' => 'بۇل ساناتتا {{PLURAL:$1|بٸر|$1}} بەت بار.', |
2148 | 2150 | 'category-media-count' => 'بۇل ساناتتا {{PLURAL:$1|بٸر|$1}} فايل بار.', |
2149 | 2151 | 'listingcontinuesabbrev' => ' (جالع.)', |
— | — | @@ -2175,7 +2177,7 @@ |
2176 | 2178 | 'rcpatroldisabledtext' => 'جۋىقتاعى ٶزگەرٸستەر كٷزەتٸ قاسيەتٸ اعىمدا ٶشٸرٸلگەن.', |
2177 | 2179 | 'markedaspatrollederror' => 'كٷزەتتە دەپ بەلگٸلەنبەيدٸ', |
2178 | 2180 | 'markedaspatrollederrortext' => 'كٷزەتتە دەپ بەلگٸلەۋ ٷشٸن نۇسقاسىن ەنگٸزٸڭٸز.', |
2179 | | -'markedaspatrollederror-noautopatrol' => 'ٶزٸڭٸزدٸڭ ٶزگەرٸستەرٸڭٸزدٸ كٷزەتكە قويا المايسىز.', |
| 2181 | +'markedaspatrollederror-noautopatrol' => 'ٶزٸڭٸز جاساعان ٶزگەرٸستەرٸڭٸزدٸ كٷزەتكە قويا المايسىز.', |
2180 | 2182 | |
2181 | 2183 | # Patrol log |
2182 | 2184 | 'patrol-log-page' => 'كٷزەت جۋرنالى', |
— | — | @@ -2192,7 +2194,7 @@ |
2193 | 2195 | |
2194 | 2196 | # Media information |
2195 | 2197 | 'mediawarning' => "'''نازار سالىڭىز''': بۇل فايل تٷرٸندە قاسكٷنەمدٸ ٵمٸردٸڭ بار بولۋى ىقتيمال; فايلدى جەگٸپ جٷيەڭٸزگە زييان كەلتٸرۋٸڭٸز مٷمكٸن.<hr />", |
2196 | | -'imagemaxsize' => 'سۋرەت تٷيٸندەمە بەتٸندەگٸ سۋرەتتٸڭ مٶلشەرٸن شەكتەۋٸ:', |
| 2198 | +'imagemaxsize' => 'سيپاتتاماسى بەتٸندەگٸ سۋرەتتٸڭ مٶلشەرٸن شەكتەۋٸ:', |
2197 | 2199 | 'thumbsize' => 'نوباي مٶلشەرٸ:', |
2198 | 2200 | 'widthheight' => '$1 × $2', |
2199 | 2201 | 'file-info' => 'فايل مٶلشەرٸ: $1, MIME تٷرٸ: $2', |
— | — | @@ -2498,7 +2500,7 @@ |
2499 | 2501 | # Pseudotags used for GPSSpeedRef and GPSDestDistanceRef |
2500 | 2502 | 'exif-gpsspeed-k' => 'km/h', |
2501 | 2503 | 'exif-gpsspeed-m' => 'mil/h', |
2502 | | -'exif-gpsspeed-n' => 'ج. تٷيٸن', |
| 2504 | +'exif-gpsspeed-n' => 'knot', |
2503 | 2505 | |
2504 | 2506 | # Pseudotags used for GPSTrackRef, GPSImgDirectionRef and GPSDestBearingRef |
2505 | 2507 | 'exif-gpsdirection-t' => 'شىن باعىت', |
Index: branches/liquidthreads/languages/messages/MessagesEn.php |
— | — | @@ -1958,7 +1958,7 @@ |
1959 | 1959 | 'istemplate' => 'inclusion', |
1960 | 1960 | 'whatlinkshere-prev' => '{{PLURAL:$1|previous|previous $1}}', |
1961 | 1961 | 'whatlinkshere-next' => '{{PLURAL:$1|next|next $1}}', |
1962 | | -'whatlinkshere-links' => '(← links)', |
| 1962 | +'whatlinkshere-links' => '← links', |
1963 | 1963 | |
1964 | 1964 | # Block/unblock IP |
1965 | 1965 | # |
Index: branches/liquidthreads/languages/messages/MessagesKk_kz.php |
— | — | @@ -166,7 +166,7 @@ |
167 | 167 | 'localmonth' => array( 1, 'ЖЕРГІЛІКТІАЙ', 'LOCALMONTH' ), |
168 | 168 | 'localmonthname' => array( 1, 'ЖЕРГІЛІКТІАЙАТАУЫ', 'LOCALMONTHNAME' ), |
169 | 169 | 'localmonthnamegen' => array( 1, 'ЖЕРГІЛІКТІАЙІЛІКАТАУЫ', 'LOCALMONTHNAMEGEN' ), |
170 | | - 'localmonthabbrev' => array( 1, 'ЖЕРГІЛІКТІАЙЖИЫР', 'ЖЕРГІЛІКТІАЙҚЫСҚА', 'LOCALMONTHABBREV' ), |
| 170 | + 'localmonthabbrev' => array( 1, 'ЖЕРГІЛІКТІАЙЖИЫР', 'ЖЕРГІЛІКТІАЙҚЫСҚАША', 'ЖЕРГІЛІКТІАЙҚЫСҚА', 'LOCALMONTHABBREV' ), |
171 | 171 | 'localday' => array( 1, 'ЖЕРГІЛІКТІКҮН', 'LOCALDAY' ), |
172 | 172 | 'localday2' => array( 1, 'ЖЕРГІЛІКТІКҮН2', 'LOCALDAY2' ), |
173 | 173 | 'localdayname' => array( 1, 'ЖЕРГІЛІКТІКҮНАТАУЫ', 'LOCALDAYNAME' ), |
— | — | @@ -188,8 +188,8 @@ |
189 | 189 | 'subjectspacee' => array( 1, 'ТАҚЫРЫПБЕТІ2', 'МАҚАЛАБЕТІ2', 'SUBJECTSPACEE', 'ARTICLESPACEE' ), |
190 | 190 | 'fullpagename' => array( 1, 'ТОЛЫҚБЕТАТАУЫ', 'FULLPAGENAME' ), |
191 | 191 | 'fullpagenamee' => array( 1, 'ТОЛЫҚБЕТАТАУЫ2', 'FULLPAGENAMEE' ), |
192 | | - 'subpagename' => array( 1, 'АСТЫҢҒЫБЕТАТАУЫ', 'SUBPAGENAME' ), |
193 | | - 'subpagenamee' => array( 1, 'АСТЫҢҒЫБЕТАТАУЫ2', 'SUBPAGENAMEE' ), |
| 192 | + 'subpagename' => array( 1, 'БЕТШЕАТАУЫ', 'АСТЫҢҒЫБЕТАТАУЫ', 'SUBPAGENAME' ), |
| 193 | + 'subpagenamee' => array( 1, 'БЕТШЕАТАУЫ2', 'АСТЫҢҒЫБЕТАТАУЫ2', 'SUBPAGENAMEE' ), |
194 | 194 | 'basepagename' => array( 1, 'НЕГІЗГІБЕТАТАУЫ', 'BASEPAGENAME' ), |
195 | 195 | 'basepagenamee' => array( 1, 'НЕГІЗГІБЕТАТАУЫ2', 'BASEPAGENAMEE' ), |
196 | 196 | 'talkpagename' => array( 1, 'ТАЛҚЫЛАУБЕТАТАУЫ', 'TALKPAGENAME' ), |
— | — | @@ -207,9 +207,10 @@ |
208 | 208 | 'img_width' => array( 1, '$1 px', '$1px' ), |
209 | 209 | 'img_center' => array( 1, 'ортаға', 'орта', 'center', 'centre' ), |
210 | 210 | 'img_framed' => array( 1, 'сүрмелі', 'framed', 'enframed', 'frame' ), |
| 211 | + 'img_frameless' => array( 1, 'сүрмесіз', 'frameless' ), |
211 | 212 | 'img_page' => array( 1, 'бет=$1', 'бет $1', 'page=$1', 'page $1' ), |
212 | 213 | 'img_upright' => array( 1, 'тікті', 'тіктік=$1', 'тіктік $1' ), |
213 | | - 'img_border' => array( 1, 'шекті' ), |
| 214 | + 'img_border' => array( 1, 'шекті' ), |
214 | 215 | 'img_baseline' => array( 1, 'негізжол', 'baseline' ), |
215 | 216 | 'img_sub' => array( 1, 'астылығы', 'аст', 'sub'), |
216 | 217 | 'img_super' => array( 1, 'үстілігі', 'үст', 'sup', 'super', 'sup' ), |
— | — | @@ -220,18 +221,18 @@ |
221 | 222 | 'img_text-bottom' => array( 1, 'мәтін-астында', 'text-bottom' ), |
222 | 223 | 'int' => array( 0, 'ІШКІ:', 'INT:' ), |
223 | 224 | 'sitename' => array( 1, 'ТОРАПАТАУЫ', 'SITENAME' ), |
224 | | - 'ns' => array( 0, 'ЕА:', 'NS:' ), |
| 225 | + 'ns' => array( 0, 'ЕА:', 'ЕСІМАЯ:', 'NS:' ), |
225 | 226 | 'localurl' => array( 0, 'ЖЕРГІЛІКТІЖАЙ:', 'LOCALURL:' ), |
226 | 227 | 'localurle' => array( 0, 'ЖЕРГІЛІКТІЖАЙ2:', 'LOCALURLE:' ), |
227 | 228 | 'server' => array( 0, 'СЕРВЕР', 'SERVER' ), |
228 | 229 | 'servername' => array( 0, 'СЕРВЕРАТАУЫ', 'SERVERNAME' ), |
229 | 230 | 'scriptpath' => array( 0, 'ӘМІРЖОЛЫ', 'SCRIPTPATH' ), |
230 | | - 'grammar' => array( 0, 'СЕПТІК:', 'GRAMMAR:' ), |
| 231 | + 'grammar' => array( 0, 'СЕПТІГІ:', 'СЕПТІК:', 'GRAMMAR:' ), |
231 | 232 | 'notitleconvert' => array( 0, '__АТАУАЛМАСТЫРҒЫЗБАУ__', '__ААБАУ__', '__NOTITLECONVERT__', '__NOTC__' ), |
232 | 233 | 'nocontentconvert' => array( 0, '__МАҒЛҰМАТАЛМАСТЫРҒЫЗБАУ__', '__МАБАУ__', '__NOCONTENTCONVERT__', '__NOCC__' ), |
233 | | - 'currentweek' => array( 1, 'АҒЫМДАҒЫАПТА', 'CURRENTWEEK' ), |
| 234 | + 'currentweek' => array( 1, 'АҒЫМДАҒЫАПТАСЫ', 'АҒЫМДАҒЫАПТА', 'CURRENTWEEK' ), |
234 | 235 | 'currentdow' => array( 1, 'АҒЫМДАҒЫАПТАКҮНІ', 'CURRENTDOW' ), |
235 | | - 'localweek' => array( 1, 'ЖЕРГІЛІКТІАПТА', 'LOCALWEEK' ), |
| 236 | + 'localweek' => array( 1, 'ЖЕРГІЛІКТІАПТАСЫ', 'ЖЕРГІЛІКТІАПТА', 'LOCALWEEK' ), |
236 | 237 | 'localdow' => array( 1, 'ЖЕРГІЛІКТІАПТАКҮНІ', 'LOCALDOW' ), |
237 | 238 | 'revisionid' => array( 1, 'НҰСҚАНӨМІРІ', 'REVISIONID' ), |
238 | 239 | 'revisionday' => array( 1, 'НҰСҚАКҮНІ' , 'REVISIONDAY' ), |
— | — | @@ -239,13 +240,13 @@ |
240 | 241 | 'revisionmonth' => array( 1, 'НҰСҚААЙЫ', 'REVISIONMONTH' ), |
241 | 242 | 'revisionyear' => array( 1, 'НҰСҚАЖЫЛЫ', 'REVISIONYEAR' ), |
242 | 243 | 'revisiontimestamp' => array( 1, 'НҰСҚАУАҚЫТТҮЙІНДЕМЕСІ', 'REVISIONTIMESTAMP' ), |
243 | | - 'plural' => array( 0, 'КӨПШЕ:', 'PLURAL:' ), |
244 | | - 'fullurl' => array( 0, 'ТОЛЫҚЖАЙ:', 'FULLURL:' ), |
245 | | - 'fullurle' => array( 0, 'ТОЛЫҚЖАЙ2:', 'FULLURLE:' ), |
246 | | - 'lcfirst' => array( 0, 'КӘ1:', 'LCFIRST:' ), |
247 | | - 'ucfirst' => array( 0, 'БӘ1:', 'UCFIRST:' ), |
248 | | - 'lc' => array( 0, 'КӘ:', 'LC:' ), |
249 | | - 'uc' => array( 0, 'БӘ:', 'UC:' ), |
| 244 | + 'plural' => array( 0, 'КӨПШЕТҮРІ:','КӨПШЕ:', 'PLURAL:' ), |
| 245 | + 'fullurl' => array( 0, 'ТОЛЫҚЖАЙЫ:', 'ТОЛЫҚЖАЙ:', 'FULLURL:' ), |
| 246 | + 'fullurle' => array( 0, 'ТОЛЫҚЖАЙЫ2:', 'ТОЛЫҚЖАЙ2:', 'FULLURLE:' ), |
| 247 | + 'lcfirst' => array( 0, 'КӘ1:', 'КІШІӘРІППЕН1:', 'LCFIRST:' ), |
| 248 | + 'ucfirst' => array( 0, 'БӘ1:', 'БАСӘРІППЕН1:', 'UCFIRST:' ), |
| 249 | + 'lc' => array( 0, 'КӘ:', 'КІШІӘРІППЕН:', 'LC:' ), |
| 250 | + 'uc' => array( 0, 'БӘ:', 'БАСӘРІППЕН:', 'UC:' ), |
250 | 251 | 'raw' => array( 0, 'ҚАМ:', 'RAW:' ), |
251 | 252 | 'displaytitle' => array( 1, 'КӨРСЕТІЛЕТІНАТАУ', 'DISPLAYTITLE' ), |
252 | 253 | 'rawsuffix' => array( 1, 'Қ', 'R' ), |
— | — | @@ -261,9 +262,9 @@ |
262 | 263 | 'pagesinnamespace' => array( 1, 'ЕСІМАЯБЕТСАНЫ:', 'ЕАБЕТСАНЫ:', 'АЯБЕТСАНЫ:', 'PAGESINNAMESPACE:', 'PAGESINNS:' ), |
263 | 264 | 'numberofadmins' => array( 1, 'ӘКІМШІСАНЫ', 'NUMBEROFADMINS' ), |
264 | 265 | 'formatnum' => array( 0, 'САНПІШІМІ', 'FORMATNUM' ), |
265 | | - 'padleft' => array( 0, 'СОЛЫҒЫС', 'PADLEFT' ), |
266 | | - 'padright' => array( 0, 'ОҢЫҒЫС', 'PADRIGHT' ), |
267 | | - 'special' => array( 0, 'арнайы', 'special', ), |
| 266 | + 'padleft' => array( 0, 'СОЛҒАЫҒЫС', 'СОЛЫҒЫС', 'PADLEFT' ), |
| 267 | + 'padright' => array( 0, 'ОҢҒАЫҒЫС', 'ОҢЫҒЫС', 'PADRIGHT' ), |
| 268 | + 'special' => array( 0, 'арнайы', 'special', ), |
268 | 269 | 'defaultsort' => array( 1, 'ӘДЕПКІСҰРЫПТАУ:', 'ӘДЕПКІСҰРЫП:', 'DEFAULTSORT:' ), |
269 | 270 | ); |
270 | 271 | |
— | — | @@ -347,7 +348,7 @@ |
348 | 349 | $messages = array( |
349 | 350 | # User preference toggles |
350 | 351 | 'tog-underline' => 'Сілтемені астынан сыз:', |
351 | | -'tog-highlightbroken' => 'Жоқталған сілтемелерді <a href="" class="new">былай</a> пішімде (басқаша: былай <a href="" class="internal">?</a> сияқты).', |
| 352 | +'tog-highlightbroken' => 'Жарамсыз сілтемелерді <a href="" class="new">былай</a> пішімде (баламасы: былай <a href="" class="internal">?</a> сияқты).', |
352 | 353 | 'tog-justify' => 'Ежелерді ені бойынша туралау', |
353 | 354 | 'tog-hideminor' => 'Жуықтағы өзгерістерде шағын түзетуді жасыр', |
354 | 355 | 'tog-extendwatchlist' => 'Бақылау тізімді ұлғайт (барлық жарамды өзгерістерді көрсет)', |
— | — | @@ -448,7 +449,7 @@ |
449 | 450 | 'categories' => 'Барлық санат тізімі', |
450 | 451 | 'pagecategories' => '{{PLURAL:$1|Санат|Санаттар}}', |
451 | 452 | 'category_header' => '«$1» санатындағы беттер', |
452 | | -'subcategories' => 'Төменгі санаттар', |
| 453 | +'subcategories' => 'Санатшалар', |
453 | 454 | 'category-media-header' => '«$1» санатындағы таспалар', |
454 | 455 | |
455 | 456 | 'linkprefix' => '/^(.*?)([a-zäçéğıïñöşüýа-яёәіңғүұқөһA-ZÄÇÉĞİÏÑÖŞÜÝА-ЯЁӘІҢҒҮҰҚӨҺʺʹ«„]+)$/sDu', |
— | — | @@ -887,7 +888,7 @@ |
888 | 889 | 'nonunicodebrowser' => '<strong>АҢҒАРТПА: Шолғышыңыз Unicode белгілеуіне үйлесімді емес, сондықтан латын емес әріптері бар беттерді өңдеу зіл болу мүмкін. Жұмыс істеуге ықтималдық беру үшін, төменгі өңдеу аумағында ASCII емес әріптер оналтылық санымен көрсетіледі</strong>.', |
889 | 890 | 'editingold' => '<strong>АҢҒАРТПА: Осы беттің ертерек нұсқасын |
890 | 891 | өңдеп жатырсыз. |
891 | | -Бұны сақтасаңыз, осы нусқадан соңғы барлық түзетулер жойылады.</strong>', |
| 892 | +Бұны сақтасаңыз, осы нусқадан соңғы барлық өзгерістер жойылады.</strong>', |
892 | 893 | 'yourdiff' => 'Айырмалар', |
893 | 894 | 'copyrightwarning' => '{{SITENAME}} жобасына қосылған бүкіл үлес $2 (көбірек ақпарат үшін: $1) құжатына сай жіберілген болып саналады. Егер жазуыңыздың еркін көшіріліп түзетілуін қаламасаңыз, мында ұсынбауыңыз жөн.<br /> |
894 | 895 | Тағы, қосқан үлесіңіз - өзіңіздің жазғанығыз, не ашық ақпарат көздерінен алынған мағлұмат болғанын уәде етесіз.<br /> |
— | — | @@ -1068,7 +1069,7 @@ |
1069 | 1070 | 'qbsettings-fixedright' => 'Оңға бекітілген', |
1070 | 1071 | 'qbsettings-floatingleft' => 'Солға қалқыған', |
1071 | 1072 | 'qbsettings-floatingright' => 'Оңға қалқыған', |
1072 | | -'changepassword' => 'Құпия сөз өзгерту', |
| 1073 | +'changepassword' => 'Құпия сөзді ауыстыру', |
1073 | 1074 | 'skin' => 'Безендіру', |
1074 | 1075 | 'math' => 'Математика', |
1075 | 1076 | 'dateformat' => 'Күн-ай пішімі', |
— | — | @@ -1150,7 +1151,7 @@ |
1151 | 1152 | 'rightsnone' => '(ешқандай)', |
1152 | 1153 | |
1153 | 1154 | # Recent changes |
1154 | | -'nchanges' => '{{PLURAL:$1|бір түзету|$1 түзету}}', |
| 1155 | +'nchanges' => '{{PLURAL:$1|бір өзгеріс|$1 өзгеріс}}', |
1155 | 1156 | 'recentchanges' => 'Жуықтағы өзгерістер', |
1156 | 1157 | 'recentchangestext' => 'Бұл бетте осы уикидегі болған жуықтағы өзгерістер байқалады.', |
1157 | 1158 | 'recentchanges-feed-description' => 'Бұл арнаменен уикидегі ең соңғы өзгерістер қадағаланады.', |
— | — | @@ -1177,9 +1178,9 @@ |
1178 | 1179 | 'rc_categories_any' => 'Қайсыбір', |
1179 | 1180 | |
1180 | 1181 | # Recent changes linked |
1181 | | -'recentchangeslinked' => 'Қатысты түзетулер', |
| 1182 | +'recentchangeslinked' => 'Қатысты өзгерістер', |
1182 | 1183 | 'recentchangeslinked-noresult' => 'Сілтеген беттерде айтылмыш мерзімде ешқандай өзгеріс болмаған.', |
1183 | | -'recentchangeslinked-summary' => "Бұл арнайы бетте сілтеген беттердегі жуықтағы өзгерістер тізімі беріледі. Бақылау тізіміңіздегі беттер '''жуан''' әрпімен белгіленеді.", |
| 1184 | +'recentchangeslinked-summary' => "Бұл арнайы бетте сілтеген беттердегі жуықтағы өзгерістер тізімі беріледі. Бақылау тізіміңіздегі беттер '''жуан''' әрбімен белгіленеді.", |
1184 | 1185 | |
1185 | 1186 | # Upload |
1186 | 1187 | 'upload' => 'Файл қотару', |
— | — | @@ -1217,8 +1218,8 @@ |
1218 | 1219 | 'filetype-missing' => 'Бұл файлдың («.jpg» сияқты) кеңейтімі жоқ.', |
1219 | 1220 | 'large-file' => 'Файлды $1 мөлшерден аспауына тырысыңыз; бұл файл мөлшері — $2.', |
1220 | 1221 | 'largefileserver' => 'Осы файлдың мөлшері сервердің қалауынан асып кеткен.', |
1221 | | -'emptyfile' => 'Қотарылған файлыңыз бос сияқты. Бұл файл атауы жансақ енгізілгенінен болуы мүмкін. Қотарғыңыз келген файл шынында да осы файл болғанын тексеріп алыңыз.', |
1222 | | -'fileexists' => 'Осындай атаулы файл бар түге. Қайта жазудың алдынан $1 тексеріп шығыңыз.', |
| 1222 | +'emptyfile' => 'Қотарылған файлыңыз бос сияқты. Бұл файл атауында қате болуы мүмкін. Осы файлды шынайы қотарғыңыз келетін тексеріп шығыңыз.', |
| 1223 | +'fileexists' => 'Осындай атаулы файл бар түге, егер бұны өзгертуге сеніміңіз жоқ болса <strong><tt>$1</tt></strong> дегенді тексеріп шығыңыз.', |
1223 | 1224 | 'fileexists-extension' => 'Ұқсасты файл атауы бар түге:<br /> |
1224 | 1225 | Қотарылатын файл атауы: <strong><tt>$1</tt></strong><br /> |
1225 | 1226 | Бар болған файл атауы: <strong><tt>$2</tt></strong><br /> |
— | — | @@ -1305,7 +1306,7 @@ |
1306 | 1307 | |
1307 | 1308 | # MIME search |
1308 | 1309 | 'mimesearch' => 'Файлды MIME түрімен іздеу', |
1309 | | -'mimesearch-summary' => 'Бұл бет файлдарды MIME түрімен сүзгілеу мүмкіндігін береді. Кірісі: «мағлұмат түрі»/«тарау түрі», мысалы <tt>image/jpeg</tt>.', |
| 1310 | +'mimesearch-summary' => 'Бұл бет файлдарды MIME түрімен сүзгілеу мүмкіндігін береді. Кірісі: «мағлұмат түрі»/«түр тарауы», мысалы <tt>image/jpeg</tt>.', |
1310 | 1311 | 'mimetype' => 'MIME түрі:', |
1311 | 1312 | 'download' => 'жүктеу', |
1312 | 1313 | |
— | — | @@ -1519,7 +1520,7 @@ |
1520 | 1521 | * [[{{ns:special}}:Watchlist/edit|Бүкіл тізімді қарау және өзгерту]]. |
1521 | 1522 | * [[{{ns:special}}:Watchlist/clear|Тізімдегі барлық дана аластату]].", |
1522 | 1523 | 'wlheader-enotif' => '* Ескерту хат жіберуі ендірілген.', |
1523 | | -'wlheader-showupdated' => "* Соңғы кіргенімнен бері түзетілген беттерді '''жуан''' мәтінмен көрсет", |
| 1524 | +'wlheader-showupdated' => "* Соңғы кіргенімнен бері өзгертілген беттерді '''жуан''' әрбімен көрсет", |
1524 | 1525 | 'watchmethod-recent' => 'бақылаулы беттердің жуықтағы өзгерістерін тексеру', |
1525 | 1526 | 'watchmethod-list' => 'жуықтағы өзгерістерде бақылаулы беттерді тексеру', |
1526 | 1527 | 'removechecked' => 'Белгіленгенді бақылау тізімінен аластату', |
— | — | @@ -1620,7 +1621,7 @@ |
1621 | 1622 | «Артқа» түймесін басыңыз, және бетті кері жүктеңіз, сосын қайталап көріңіз.', |
1622 | 1623 | 'protectlogpage' => 'Қорғау_журналы', |
1623 | 1624 | 'protectlogtext' => 'Төменде беттердің қорғау/қорғамау тізімі берілген. Ағымдағы қорғау әректтер бар беттер үшін [[{{ns:special}}:Protectedpages|қорғалған бет тізімін]] қараңыз.', |
1624 | | -'protectedarticle' => '«$1» қорғалды', |
| 1625 | +'protectedarticle' => '«[[$1]]» қорғалды', |
1625 | 1626 | 'unprotectedarticle' => '«[[$1]]» қорғалмады', |
1626 | 1627 | 'protectsub' => '(«$1» қорғауда)', |
1627 | 1628 | 'confirmprotecttext' => 'Осы бетті расында да қорғау қажет пе?', |
— | — | @@ -1650,7 +1651,7 @@ |
1651 | 1652 | 'protect-expiring' => 'бітуі: $1 (UTC)', |
1652 | 1653 | 'protect-cascade' => 'Баулы қорғау — бұл бетке кірістірілген әрқайсы беттерді қорғау.', |
1653 | 1654 | 'restriction-type' => 'Рұқсаты:', |
1654 | | -'restriction-level' => 'Рұқсат деңгейі:', |
| 1655 | +'restriction-level' => 'Рұқсат шектеу деңгейі:', |
1655 | 1656 | 'minimum-size' => 'Ең аз мөлшері', |
1656 | 1657 | 'maximum-size' => 'Ең көп мөлшері', |
1657 | 1658 | 'pagesize' => '(байт)', |
— | — | @@ -1694,7 +1695,7 @@ |
1695 | 1696 | 'undeletedarticle' => '«[[$1]]» қайтарды', |
1696 | 1697 | 'undeletedrevisions' => '{{PLURAL:$1|Нұсқаны|$1 нұсқаны}} қайтарды', |
1697 | 1698 | 'undeletedrevisions-files' => '{{PLURAL:$1|Нұсқаны|$1 нұсқаны}} және {{PLURAL:$2|файлды|$2 файлды}} қайтарды', |
1698 | | -'undeletedfiles' => '{{PLURAL:$1|1 файл|$1 файл}} қайтарды', |
| 1699 | +'undeletedfiles' => '{{PLURAL:$1|1 файлды|$1 файлды}} қайтарды', |
1699 | 1700 | 'cannotundelete' => 'Қайтару сәтсіз бітті; тағы біреу сізден бұрын сол бетті қайтарған болар.', |
1700 | 1701 | 'undeletedpage' => "<big>'''$1 қайтарылды'''</big> |
1701 | 1702 | |
— | — | @@ -1714,8 +1715,8 @@ |
1715 | 1716 | 'mycontris' => 'Үлесім', |
1716 | 1717 | 'contribsub2' => '$1 ($2) үлесі', |
1717 | 1718 | 'nocontribs' => 'Осы іздеу шартына сәйкес өзгерістер табылған жоқ.', |
1718 | | -'ucnote' => 'Төменде осы қатысушының соңғы <b>$2</b> күндегі, соңғы <b>$1</b> өзгерісі көрсетледі.', |
1719 | | -'uclinks' => 'Соңғы $2 күндегі, соңғы $1 өзгерісін қарау.', |
| 1719 | +'ucnote' => 'Төменде осы қатысушы жасаған соңғы <b>$2</b> күндегі, соңғы <b>$1</b> өзгерісі көрсетледі.', |
| 1720 | +'uclinks' => 'Соңғы $2 күндегі, соңғы жасалған $1 өзгерісін қарау.', |
1720 | 1721 | 'uctop' => ' (үсті)', |
1721 | 1722 | |
1722 | 1723 | 'sp-contributions-newest' => 'Ең жаңасына', |
— | — | @@ -1745,6 +1746,7 @@ |
1746 | 1747 | 'istemplate' => 'кіріктіру', |
1747 | 1748 | 'whatlinkshere-prev' => '{{PLURAL:$1|алдыңғы|алдыңғы $1}}', |
1748 | 1749 | 'whatlinkshere-next' => '{{PLURAL:$1|келесі|келесі $1}}', |
| 1750 | +'whatlinkshere-links' => '← сілтемелер', |
1749 | 1751 | |
1750 | 1752 | # Block/unblock |
1751 | 1753 | 'blockip' => 'Пайдаланушыны бұғаттау', |
— | — | @@ -1864,8 +1866,8 @@ |
1865 | 1867 | 'movepagetext' => "Төмендегі үлгітті қолданып беттерді қайта атайды, |
1866 | 1868 | барлық тарихын жаңа атауға жылжытады. |
1867 | 1869 | Бұрынғы бет атауы жаңа атауға айдататын бет болады. |
1868 | | -Ескі атауына сілтейтін сілтемелер өзгертілмейді; жылжытудан соң |
1869 | | -шынжырлы айдатулар бар-жоғын тексеріңіз. |
| 1870 | +Ескі атауына сілтейтін сілтемелер өзгертілмейді; жылжытудан соң |
| 1871 | +шынжырлы не жарамсыз айдатулар бар-жоғын тексеріп шығыңыз. |
1870 | 1872 | Сілтемелер бұрынғы жолдауымен былайғы өтуін тексеруіне |
1871 | 1873 | сіз міндетті боласыз. |
1872 | 1874 | |
— | — | @@ -1876,7 +1878,7 @@ |
1877 | 1879 | бірақ бар беттің үстіне жазуға болмайды. |
1878 | 1880 | |
1879 | 1881 | <b>НАЗАР САЛЫҢЫЗ!</b> |
1880 | | -Бұл дәріпті бетке қатаң және кенет өзгеріс жасауға мүмкін; |
| 1882 | +Бұл әйгілі бетке қатаң және кенет өзгеріс жасауға мүмкін; |
1881 | 1883 | әрекеттің алдынан осының зардаптарын түсінгеніңізге батыл |
1882 | 1884 | болыңыз.", |
1883 | 1885 | 'movepagetalktext' => "Келесі себептер '''болғанша''' дейін, талқылау беті өздіктік бірге жылжытылады: |
— | — | @@ -2041,8 +2043,8 @@ |
2042 | 2044 | 'tooltip-ca-nstab-help' => 'Анықтыма бетін қарау', |
2043 | 2045 | 'tooltip-ca-nstab-category' => 'Санат бетін қарау', |
2044 | 2046 | 'tooltip-minoredit' => 'Осыны шағын түзету деп белгілеу', |
2045 | | -'tooltip-save' => 'Түзетуіңізді сақтау', |
2046 | | -'tooltip-preview' => 'Сақтаудың алдынан түзетуіңізді қарап шығыңыз!', |
| 2047 | +'tooltip-save' => 'Жасаған өзгерістеріңізді сақтау', |
| 2048 | +'tooltip-preview' => 'Сақтаудың алдынан жасаған өзгерістеріңізді қарап шығыңыз!', |
2047 | 2049 | 'tooltip-diff' => 'Мәтінге қандай өзгерістерді жасағаныңызды қарау.', |
2048 | 2050 | 'tooltip-compareselectedversions' => 'Беттің екі нұсқасының айырмасын қарау.', |
2049 | 2051 | 'tooltip-watch' => 'Бұл бетті бақылау тізіміңізге үстеу', |
— | — | @@ -2134,7 +2136,7 @@ |
2135 | 2137 | 'spamprotectiontitle' => '«Спам»-нан қорғайтын сүзгі', |
2136 | 2138 | 'spamprotectiontext' => 'Бұл беттің сақтауын «спам» сүзгісі бұғаттады. Бұның себебі сыртқы торап сілтемесінен болуы мүмкін.', |
2137 | 2139 | 'spamprotectionmatch' => 'Келесі «спам» мәтіні сүзгіленген: $1', |
2138 | | -'subcategorycount' => 'Бұл санатта {{PLURAL:$1|бір|$1}} төменгі санат бар.', |
| 2140 | +'subcategorycount' => 'Бұл санатта {{PLURAL:$1|бір|$1}} санатша бар.', |
2139 | 2141 | 'categoryarticlecount' => 'Бұл санатта {{PLURAL:$1|бір|$1}} бет бар.', |
2140 | 2142 | 'category-media-count' => 'Бұл санатта {{PLURAL:$1|бір|$1}} файл бар.', |
2141 | 2143 | 'listingcontinuesabbrev' => ' (жалғ.)', |
— | — | @@ -2167,7 +2169,7 @@ |
2168 | 2170 | 'rcpatroldisabledtext' => 'Жуықтағы өзгерістер Күзеті қасиеті ағымда өшірілген.', |
2169 | 2171 | 'markedaspatrollederror' => 'Күзетте деп белгіленбейді', |
2170 | 2172 | 'markedaspatrollederrortext' => 'Күзетте деп белгілеу үшін нұсқасын енгізіңіз.', |
2171 | | -'markedaspatrollederror-noautopatrol' => 'Өзіңіздің өзгерістеріңізді күзетке қоя алмайсыз.', |
| 2173 | +'markedaspatrollederror-noautopatrol' => 'Өзіңіз жасаған өзгерістеріңізді күзетке қоя алмайсыз.', |
2172 | 2174 | |
2173 | 2175 | # Patrol log |
2174 | 2176 | 'patrol-log-page' => 'Күзет журналы', |
— | — | @@ -2184,7 +2186,7 @@ |
2185 | 2187 | |
2186 | 2188 | # Media information |
2187 | 2189 | 'mediawarning' => "'''Назар салыңыз''': Бұл файл түрінде қаскүнемді әмірдің бар болуы ықтимал; файлды жегіп жүйеңізге зиян келтіруіңіз мүмкін.<hr />", |
2188 | | -'imagemaxsize' => 'Сурет түйіндеме бетіндегі суреттің мөлшерін шектеуі:', |
| 2190 | +'imagemaxsize' => 'Сипаттамасы бетіндегі суреттің мөлшерін шектеуі:', |
2189 | 2191 | 'thumbsize' => 'Нобай мөлшері:', |
2190 | 2192 | 'widthheight' => '$1 × $2', |
2191 | 2193 | 'file-info' => 'Файл мөлшері: $1, MIME түрі: $2', |
— | — | @@ -2490,7 +2492,7 @@ |
2491 | 2493 | # Pseudotags used for GPSSpeedRef and GPSDestDistanceRef |
2492 | 2494 | 'exif-gpsspeed-k' => 'km/h', |
2493 | 2495 | 'exif-gpsspeed-m' => 'mil/h', |
2494 | | -'exif-gpsspeed-n' => 'Ж. түйін', |
| 2496 | +'exif-gpsspeed-n' => 'knot', |
2495 | 2497 | |
2496 | 2498 | # Pseudotags used for GPSTrackRef, GPSImgDirectionRef and GPSDestBearingRef |
2497 | 2499 | 'exif-gpsdirection-t' => 'Шын бағыт', |
Index: branches/liquidthreads/languages/messages/MessagesKa.php |
— | — | @@ -37,859 +37,533 @@ |
38 | 38 | ); |
39 | 39 | |
40 | 40 | $messages = array( |
41 | | - |
42 | 41 | # User preference toggles |
43 | | -'tog-underline' => 'ბმულებზე გაზის გასმა:', |
44 | | -'tog-highlightbroken' => 'აჩვენე არარსებული ბმულები <a href="" class="new">როგორც ეს</a> (ალტერნატივა: როგორც ეს<a href="" class="internal">?</a>).', |
45 | | -#TODO: 'tog-justify' => 'Justify paragraphs', |
46 | | -'tog-hideminor' => 'უკანასკნელ ცვლილებებში მცირე რედაქტირებების დამალვა', |
47 | | -'tog-extendwatchlist' => 'განავრცეთ კონტროლის სია ისე, რომ აჩვენოთ ყველა შესაძლებელი ცვლილება', |
48 | | -'tog-usenewrc' => 'გაზარდეთ ბოლო ცვლილებების სია (ჯავასკრიპტი)', |
49 | | -'tog-numberheadings' => 'სათაურების ავტომატურად გადანომვრა', |
50 | | -'tog-showtoolbar' => 'სარედაქტორო ინსტრუმენტების პანელის (ჯავასკრიპტი) ჩვენება', |
51 | | -'tog-editondblclick' => 'გვერდების რედაქტირება მოახდინეთ ორმაგი დაჭერით (ჯავასკრიპტი)', |
52 | | -'tog-editsection' => 'ნება დართეთ სექციის რედაქტირებაზე \'[რედაქტირება]\' ბმულების გავლით', |
53 | | -'tog-editsectiononrightclick' => 'ნება დართეთ სექციის რედაქტირებაზე მარჯვენა ღილაკზე დაჭერით<br />სექციის სათაურებზე (ჯავასკრიპტი)', |
54 | | -'tog-showtoc' => 'აჩვენეთ სარჩევი ცხრილი (იმ გვერდებისათვის, რომელსაც სამზე მეტი სათაური აქვთ)', |
55 | | -'tog-rememberpassword' => 'სესიებს შორის პაროლის დამახსოვრება', |
56 | | -'tog-editwidth' => 'სარედაქტირო ყუთს აქვს სრული სიგანე', |
57 | | -'tog-watchcreations' => 'გვერდები, რომელიც მე გავხსენი, დაამატეთ ჩემს საკონტროლო სიას', |
58 | | -'tog-watchdefault' => 'დამალეთ რობოტის რედაქტირებები საკონტროლო სიიდან', |
59 | | -#TODO: 'tog-watchmoves' => 'Add pages I move to my watchlist', |
60 | | -#TODO: 'tog-watchdeletion' => 'Add pages I delete to my watchlist', |
61 | | -#TODO: 'tog-minordefault' => 'Mark all edits minor by default', |
62 | | -'tog-previewontop' => 'რედაქტირების ფანჯრამდე წინასწარი ხედვის ჩვენება', |
63 | | -'tog-previewonfirst' => 'პირველი რედაქტიებისას წინასწარი გადახედვის ჩვენება', |
64 | | -#TODO: 'tog-nocache' => 'Disable page caching', |
65 | | -'tog-enotifwatchlistpages' => 'მომწერეთ როდესაც გვერდი, რომელსაც მე ვაკონტროლებ შეიცვლება', |
66 | | -'tog-enotifusertalkpages' => 'მომწერეთ, როდესაც ჩემი მომხმარებლის განხილვის გვერდი შეიცვლება', |
67 | | -'tog-enotifminoredits' => 'მომწერეთ ასევე მცირე რედაქტირებების შესახებ გვერდებზე', |
68 | | -'tog-enotifrevealaddr' => 'ჩემი ელ. ფოსტის მისამართი შეხსენებების წერილებში აჩვენეთ', |
69 | | -'tog-shownumberswatching' => 'კონტროლის ქვეშ მყოფი მომხმარებელთა რაოდენობის ჩვენება', |
70 | | -'tog-fancysig' => 'გამოუყენებელი ხელმოწერები (ავტომატური ბმულის გარეშე)', |
71 | | -#TODO: 'tog-externaleditor' => 'Use external editor by default', |
72 | | -#TODO: 'tog-externaldiff' => 'Use external diff by default', |
73 | | -'tog-showjumplinks' => 'დამხმარე ბმულების "გადასვლა -კენ" ჩართვა', |
74 | | -'tog-uselivepreview' => 'გამოიყენეთ ახალი წინასწარი გადახედვა (ჯავასკრიპტი) (ექსპერიმენტული)', |
75 | | -#TODO: 'tog-forceeditsummary' => 'Prompt me when entering a blank edit summary', |
76 | | -'tog-watchlisthideown' => 'დამალეთ საკონტროლო სიიდან ჩემი რედაქტირებები', |
77 | | -'tog-watchlisthidebots' => 'დამალეთ საკონტროლო სიიდან ჩემი რედაქტირებები', |
78 | | -'tog-watchlisthideminor' => 'დამალეთ საკონტროლო სიიდან მცირე რედაქტირებები', |
79 | | -#TODO: 'tog-nolangconversion' => 'Disable variants conversion', |
80 | | -#TODO: 'tog-ccmeonemails' => 'Send me copies of emails I send to other users', |
81 | | -#TODO: 'tog-diffonly' => "Don't show page content below diffs", |
| 42 | +'tog-underline' => 'ბმულებზე გაზის გასმა:', |
| 43 | +'tog-highlightbroken' => 'აჩვენე არარსებული ბმულები <a href="" class="new">როგორც ეს</a> (ალტერნატივა: როგორც ეს<a href="" class="internal">?</a>).', |
| 44 | +'tog-hideminor' => 'უკანასკნელ ცვლილებებში მცირე რედაქტირებების დამალვა', |
| 45 | +'tog-extendwatchlist' => 'განავრცეთ კონტროლის სია ისე, რომ აჩვენოთ ყველა შესაძლებელი ცვლილება', |
| 46 | +'tog-usenewrc' => 'გაზარდეთ ბოლო ცვლილებების სია (ჯავასკრიპტი)', |
| 47 | +'tog-numberheadings' => 'სათაურების ავტომატურად გადანომვრა', |
| 48 | +'tog-showtoolbar' => 'სარედაქტორო ინსტრუმენტების პანელის (ჯავასკრიპტი) ჩვენება', |
| 49 | +'tog-editondblclick' => 'გვერდების რედაქტირება მოახდინეთ ორმაგი დაჭერით (ჯავასკრიპტი)', |
| 50 | +'tog-editsection' => "ნება დართეთ სექციის რედაქტირებაზე '[რედაქტირება]' ბმულების გავლით", |
| 51 | +'tog-editsectiononrightclick' => 'ნება დართეთ სექციის რედაქტირებაზე მარჯვენა ღილაკზე დაჭერით<br />სექციის სათაურებზე (ჯავასკრიპტი)', |
| 52 | +'tog-showtoc' => 'აჩვენეთ სარჩევი ცხრილი (იმ გვერდებისათვის, რომელსაც სამზე მეტი სათაური აქვთ)', |
| 53 | +'tog-rememberpassword' => 'სესიებს შორის პაროლის დამახსოვრება', |
| 54 | +'tog-editwidth' => 'სარედაქტირო ყუთს აქვს სრული სიგანე', |
| 55 | +'tog-watchcreations' => 'გვერდები, რომელიც მე გავხსენი, დაამატეთ ჩემს საკონტროლო სიას', |
| 56 | +'tog-watchdefault' => 'დამალეთ ბოტის რედაქტირებები საკონტროლო სიიდან', |
| 57 | +'tog-previewontop' => 'რედაქტირების ფანჯრამდე წინასწარი ხედვის ჩვენება', |
| 58 | +'tog-previewonfirst' => 'პირველი რედაქტიებისას წინასწარი გადახედვის ჩვენება', |
| 59 | +'tog-enotifwatchlistpages' => 'მომწერეთ როდესაც გვერდი, რომელსაც მე ვაკონტროლებ შეიცვლება', |
| 60 | +'tog-enotifusertalkpages' => 'მომწერეთ, როდესაც ჩემი მომხმარებლის განხილვის გვერდი შეიცვლება', |
| 61 | +'tog-enotifminoredits' => 'მომწერეთ ასევე მცირე რედაქტირებების შესახებ გვერდებზე', |
| 62 | +'tog-enotifrevealaddr' => 'ჩემი ელ. ფოსტის მისამართი შეხსენებების წერილებში აჩვენეთ', |
| 63 | +'tog-shownumberswatching' => 'კონტროლის ქვეშ მყოფი მომხმარებელთა რაოდენობის ჩვენება', |
| 64 | +'tog-fancysig' => 'გამოუყენებელი ხელმოწერები (ავტომატური ბმულის გარეშე)', |
| 65 | +'tog-showjumplinks' => 'დამხმარე ბმულების "გადასვლა -კენ" ჩართვა', |
| 66 | +'tog-uselivepreview' => 'გამოიყენეთ ახალი წინასწარი გადახედვა (ჯავასკრიპტი) (ექსპერიმენტული)', |
| 67 | +'tog-watchlisthideown' => 'დამალეთ საკონტროლო სიიდან ჩემი რედაქტირებები', |
| 68 | +'tog-watchlisthidebots' => 'დამალეთ საკონტროლო სიიდან ჩემი რედაქტირებები', |
| 69 | +'tog-watchlisthideminor' => 'დამალეთ საკონტროლო სიიდან მცირე რედაქტირებები', |
82 | 70 | |
83 | 71 | 'underline-always' => 'ყოველთვის', |
84 | | -'underline-never' => 'არასოდეს', |
85 | | -#TODO: 'underline-default' => 'Browser default', |
| 72 | +'underline-never' => 'არასოდეს', |
86 | 73 | |
87 | 74 | 'skinpreview' => '(წინასწარი გადახედვა)', |
88 | 75 | |
89 | 76 | # Dates |
90 | | -'sunday' => 'კვირა', |
91 | | -'monday' => 'ორშაბათი', |
92 | | -'tuesday' => 'სამშაბათი', |
93 | | -'wednesday' => 'ოთხშაბათი', |
94 | | -'thursday' => 'ხუთშაბათი', |
95 | | -'friday' => 'პარასკევი', |
96 | | -'saturday' => 'შაბათი', |
97 | | -'sun' => 'კვი', |
98 | | -'mon' => 'ორშ', |
99 | | -'tue' => 'სამ', |
100 | | -'wed' => 'ოთხ', |
101 | | -'thu' => 'ხუთ', |
102 | | -'fri' => 'პარ', |
103 | | -'sat' => 'შაბ', |
104 | | -'january' => 'იანვარი', |
105 | | -'february' => 'თებერვალი', |
106 | | -'march' => 'მარტი', |
107 | | -'april' => 'აპრილი', |
108 | | -'may_long' => 'მაისი', |
109 | | -'june' => 'ივნისი', |
110 | | -'july' => 'ივლისი', |
111 | | -'august' => 'აგვისტო', |
112 | | -'september' => 'სექტემბერი', |
113 | | -'october' => 'ოქტომბერი', |
114 | | -'november' => 'ნოემბერი', |
115 | | -'december' => 'დეკემბერი', |
116 | | -'january-gen' => 'იანვრის', |
117 | | -'february-gen' => 'თებერვლის', |
118 | | -'march-gen' => 'მარტის', |
119 | | -'april-gen' => 'აპრილის', |
120 | | -'may-gen' => 'მაისის', |
121 | | -'june-gen' => 'ივნისის', |
122 | | -'july-gen' => 'ივლისის', |
123 | | -'august-gen' => 'აგვისტოს', |
124 | | -'september-gen' => 'სექტემბრის', |
125 | | -'october-gen' => 'ოქტომბრის', |
126 | | -'november-gen' => 'ნოემბრის', |
127 | | -'december-gen' => 'დეკემბრის', |
128 | | -'jan' => 'იან', |
129 | | -'feb' => 'თებ', |
130 | | -'mar' => 'მარ', |
131 | | -'apr' => 'აპრ', |
132 | | -'may' => 'მაი', |
133 | | -'jun' => 'ივნ', |
134 | | -'jul' => 'ივლ', |
135 | | -'aug' => 'აგვ', |
136 | | -'sep' => 'სექ', |
137 | | -'oct' => 'ოქტ', |
138 | | -'nov' => 'ნოე', |
139 | | -'dec' => 'დეკ', |
| 77 | +'sunday' => 'კვირა', |
| 78 | +'monday' => 'ორშაბათი', |
| 79 | +'tuesday' => 'სამშაბათი', |
| 80 | +'wednesday' => 'ოთხშაბათი', |
| 81 | +'thursday' => 'ხუთშაბათი', |
| 82 | +'friday' => 'პარასკევი', |
| 83 | +'saturday' => 'შაბათი', |
| 84 | +'sun' => 'კვი', |
| 85 | +'mon' => 'ორშ', |
| 86 | +'tue' => 'სამ', |
| 87 | +'wed' => 'ოთხ', |
| 88 | +'thu' => 'ხუთ', |
| 89 | +'fri' => 'პარ', |
| 90 | +'sat' => 'შაბ', |
| 91 | +'january' => 'იანვარი', |
| 92 | +'february' => 'თებერვალი', |
| 93 | +'march' => 'მარტი', |
| 94 | +'april' => 'აპრილი', |
| 95 | +'may_long' => 'მაისი', |
| 96 | +'june' => 'ივნისი', |
| 97 | +'july' => 'ივლისი', |
| 98 | +'august' => 'აგვისტო', |
| 99 | +'september' => 'სექტემბერი', |
| 100 | +'october' => 'ოქტომბერი', |
| 101 | +'november' => 'ნოემბერი', |
| 102 | +'december' => 'დეკემბერი', |
| 103 | +'january-gen' => 'იანვრის', |
| 104 | +'february-gen' => 'თებერვლის', |
| 105 | +'march-gen' => 'მარტის', |
| 106 | +'april-gen' => 'აპრილის', |
| 107 | +'may-gen' => 'მაისის', |
| 108 | +'june-gen' => 'ივნისის', |
| 109 | +'july-gen' => 'ივლისის', |
| 110 | +'august-gen' => 'აგვისტოს', |
| 111 | +'september-gen' => 'სექტემბრის', |
| 112 | +'october-gen' => 'ოქტომბრის', |
| 113 | +'november-gen' => 'ნოემბრის', |
| 114 | +'december-gen' => 'დეკემბრის', |
| 115 | +'jan' => 'იან', |
| 116 | +'feb' => 'თებ', |
| 117 | +'mar' => 'მარ', |
| 118 | +'apr' => 'აპრ', |
| 119 | +'may' => 'მაი', |
| 120 | +'jun' => 'ივნ', |
| 121 | +'jul' => 'ივლ', |
| 122 | +'aug' => 'აგვ', |
| 123 | +'sep' => 'სექ', |
| 124 | +'oct' => 'ოქტ', |
| 125 | +'nov' => 'ნოე', |
| 126 | +'dec' => 'დეკ', |
140 | 127 | |
141 | | -# Bits of text used by many pages: |
142 | | -'categories' => 'კატეგორიები', |
143 | | -'pagecategories' => '{{PLURAL:$1|კატეგორია|კატეგორიები}}', |
| 128 | +# Bits of text used by many pages |
| 129 | +'categories' => 'კატეგორიები', |
| 130 | +'pagecategories' => '{{PLURAL:$1|კატეგორია|კატეგორიები}}', |
144 | 131 | 'category_header' => 'სტატიები კატეგორიაში "$1"', |
145 | | -'subcategories' => 'ქვეკატეგორიები', |
| 132 | +'subcategories' => 'ქვეკატეგორიები', |
146 | 133 | |
147 | | - |
148 | 134 | 'linkprefix' => '/^(.*?)(„|«)$/sD', |
149 | | -'mainpage' => 'მთავარი გვერდი', |
150 | | -#TODO: 'mainpagetext' => "<big>'''MediaWiki has been successfully installed.'''</big>", |
151 | | -/*TODO: 'mainpagedocfooter' => "Consult the [http://meta.wikimedia.org/wiki/Help:Contents User's Guide] for information on using the wiki software. |
152 | 135 | |
153 | | -== Getting started == |
| 136 | +'about' => 'შესახებ', |
| 137 | +'article' => 'სტატია', |
| 138 | +'newwindow' => '(ახალ ფანჯარაში)', |
| 139 | +'cancel' => 'გაუქმება', |
| 140 | +'qbfind' => 'ძებნა', |
| 141 | +'qbbrowse' => 'მიმოხილვა', |
| 142 | +'qbedit' => 'რედაქტირება', |
| 143 | +'qbpageoptions' => 'ეს გვერდი', |
| 144 | +'qbpageinfo' => 'კონტექსტი', |
| 145 | +'qbmyoptions' => 'ჩემი გვერდები', |
| 146 | +'qbspecialpages' => 'სპეციალური გვერდები', |
| 147 | +'moredotdotdot' => 'მეტი...', |
| 148 | +'mypage' => 'ჩემი გვერდი', |
| 149 | +'mytalk' => 'ჩემი განხილვა', |
| 150 | +'anontalk' => 'ამ IP-ს განხილვა', |
| 151 | +'navigation' => 'ნავიგაცია', |
154 | 152 | |
155 | | -* [http://www.mediawiki.org/wiki/Help:Configuration_settings Configuration settings list] |
156 | | -* [http://www.mediawiki.org/wiki/Help:FAQ MediaWiki FAQ] |
157 | | -* [http://mail.wikimedia.org/mailman/listinfo/mediawiki-announce MediaWiki release mailing list]",*/ |
| 153 | +'errorpagetitle' => 'შეცდომა', |
| 154 | +'returnto' => '$1-ზე დაბრუნება.', |
| 155 | +'tagline' => '{{SITENAME}}დან', |
| 156 | +'help' => 'დახმარება', |
| 157 | +'search' => 'ძიება', |
| 158 | +'searchbutton' => 'ძიება', |
| 159 | +'go' => 'გვერდი', |
| 160 | +'searcharticle' => 'გვერდი', |
| 161 | +'history' => 'გვერდის ისტორია', |
| 162 | +'history_short' => 'ისტორია', |
| 163 | +'updatedmarker' => 'ჩემი უკანასკნელი შემოსვლიდან ცვლილებები', |
| 164 | +'info_short' => 'ინფორმაცია', |
| 165 | +'printableversion' => 'დასაბეჭდი ვერსია', |
| 166 | +'permalink' => 'მუდმივი ბმული', |
| 167 | +'print' => 'ბეჭდვა', |
| 168 | +'edit' => 'რედაქტირება', |
| 169 | +'editthispage' => 'ამ გვერდის რედაქტირება', |
| 170 | +'delete' => 'წაშლა', |
| 171 | +'deletethispage' => 'ამ გვერდის წაშლა', |
| 172 | +'undelete_short' => '$1 ცვლილების აღდგენა', |
| 173 | +'protect' => 'დაცვა', |
| 174 | +'unprotect' => 'დაცვის მოხსნა', |
| 175 | +'unprotectthispage' => 'გვერდის დაცვის მოხსნა', |
| 176 | +'newpage' => 'ახალი გვერდი', |
| 177 | +'talkpage' => 'განიხილეთ ეს გვერდი', |
| 178 | +'talkpagelinktext' => 'განხილვა', |
| 179 | +'specialpage' => 'სპეციალური გვერდი', |
| 180 | +'postcomment' => 'დაურთეთ კომენტარი', |
| 181 | +'articlepage' => 'სტატიის ნახვა', |
| 182 | +'talk' => 'განხილვა', |
| 183 | +'toolbox' => 'ხელსაწყოები', |
| 184 | +'userpage' => 'მომხმარებლის გვერდის ხილვა', |
| 185 | +'projectpage' => 'პროექტის გვერდის ხილვა', |
| 186 | +'imagepage' => 'სურათის გვერდის ნახვა', |
| 187 | +'categorypage' => 'კატეგორიის გვერდის ხილვა', |
| 188 | +'otherlanguages' => 'სხვა ენებზე', |
| 189 | +'redirectedfrom' => '(გადამისამართდა გვერდიდან $1)', |
| 190 | +'redirectpagesub' => 'გადამისამართების გვერდი', |
| 191 | +'lastmodifiedat' => 'ეს გვერდი ბოლოს განახლდა $2, $1.', # $1 date, $2 time |
| 192 | +'jumptonavigation' => 'ნავიგაცია', |
| 193 | +'jumptosearch' => 'ძიება', |
158 | 194 | |
159 | | -'portal' => 'საზოგადოების პორტალი', |
160 | | -'portal-url' => '{{ns:project}}:საზოგადოების პორტალი', |
161 | | -'about' => 'შესახებ', |
162 | | -'aboutsite' => '{{SITENAME}}-ის შესახებ', |
163 | | -'aboutpage' => 'პროექტი:შესახებ', |
164 | | -'article' => 'სტატია', |
165 | | -'help' => 'დახმარება', |
166 | | -'helppage' => '{{ns:project}}:დახმარება', |
167 | | -'bugreports' => 'ანგარიში შეცდომის შესახებ', |
168 | | -'bugreportspage' => '{{ns:project}}:ანგარიში შეცდომის შესახებ', |
169 | | -'sitesupport' => 'შეწირულობები', |
170 | | -'sitesupport-url' => '{{ns:project}}:შეწირულობები', |
171 | | -'faq' => 'ხშირი შეკითხვები', |
172 | | -'faqpage' => '{{ns:project}}:ხშირი შეკითხვები', |
173 | | -'edithelp' => 'რედაქტირების დახმარება', |
174 | | -'newwindow' => '(ახალ ფანჯარაში)', |
175 | | -'edithelppage' => '{{ns:project}}:რედაქტირების დახმარება', |
176 | | -'cancel' => 'გაუქმება', |
177 | | -'qbfind' => 'ძებნა', |
178 | | -'qbbrowse' => 'მიმოხილვა', |
179 | | -'qbedit' => 'რედაქტირება', |
180 | | -'qbpageoptions' => 'ეს გვერდი', |
181 | | -'qbpageinfo' => 'კონტექსტი', |
182 | | -'qbmyoptions' => 'ჩემი გვერდები', |
183 | | -'qbspecialpages' => 'სპეციალური გვერდები', |
184 | | -'moredotdotdot' => 'მეტი...', |
185 | | -'mypage' => 'ჩემი გვერდი', |
186 | | -'mytalk' => 'ჩემი განხილვა', |
187 | | -'anontalk' => 'ამ IP-ს განხილვა', |
188 | | -'navigation' => 'ნავიგაცია', |
189 | | - |
190 | | -# Metadata in edit box |
191 | | -#TODO: 'metadata_help' => 'Metadata (see [[{{ns:project}}:Metadata]] for an explanation):', |
192 | | - |
193 | | -'currentevents' => 'ახალი ამბები', |
| 195 | +# All link text and link target definitions of links into project namespace that get used by other message strings, with the exception of user group pages (see grouppage) and the disambiguation template definition (see disambiguations). |
| 196 | +'aboutsite' => '{{SITENAME}}-ის შესახებ', |
| 197 | +'aboutpage' => 'პროექტი:შესახებ', |
| 198 | +'bugreports' => 'ანგარიში შეცდომის შესახებ', |
| 199 | +'bugreportspage' => '{{ns:project}}:ანგარიში შეცდომის შესახებ', |
| 200 | +'currentevents' => 'ახალი ამბები', |
194 | 201 | 'currentevents-url' => 'ახალი ამბები', |
| 202 | +'disclaimers' => 'პასუხისმგებლობის უარყოფა', |
| 203 | +'disclaimerpage' => '{{ns:project}}:პასუხისმგებლობის უარყოფა', |
| 204 | +'edithelp' => 'რედაქტირების დახმარება', |
| 205 | +'edithelppage' => '{{ns:project}}:რედაქტირების დახმარება', |
| 206 | +'faq' => 'ხშირი შეკითხვები', |
| 207 | +'faqpage' => '{{ns:project}}:ხშირი შეკითხვები', |
| 208 | +'helppage' => '{{ns:project}}:დახმარება', |
| 209 | +'mainpage' => 'მთავარი გვერდი', |
| 210 | +'portal' => 'საზოგადოების პორტალი', |
| 211 | +'portal-url' => '{{ns:project}}:საზოგადოების პორტალი', |
| 212 | +'privacy' => 'კონფიდენციალურობის პოლიტიკა', |
| 213 | +'privacypage' => '{{ns:project}}:კონფიდენციალურობის პოლიტიკა', |
| 214 | +'sitesupport' => 'შეწირულობები', |
| 215 | +'sitesupport-url' => '{{ns:project}}:შეწირულობები', |
195 | 216 | |
196 | | -'disclaimers' => 'პასუხისმგებლობის უარყოფა', |
197 | | -'disclaimerpage' => '{{ns:project}}:პასუხისმგებლობის უარყოფა', |
198 | | -'privacy' => 'კონფიდენციალურობის პოლიტიკა', |
199 | | -'privacypage' => '{{ns:project}}:კონფიდენციალურობის პოლიტიკა', |
200 | | -'errorpagetitle' => 'შეცდომა', |
201 | | -'returnto' => '$1-ზე დაბრუნება.', |
202 | | -'tagline' => '{{SITENAME}}დან', |
203 | | -'help' => 'დახმარება', |
204 | | -'search' => 'ძიება', |
205 | | -'searchbutton' => 'ძიება', |
206 | | -'go' => 'გვერდი', |
207 | | -'searcharticle' => 'გვერდი', |
208 | | -'history' => 'გვერდის ისტორია', |
209 | | -'history_short' => 'ისტორია', |
210 | | -'updatedmarker' => 'ჩემი უკანასკნელი შემოსვლიდან ცვლილებები', |
211 | | -'info_short' => 'ინფორმაცია', |
212 | | -'printableversion' => 'დასაბეჭდი ვერსია', |
213 | | -'permalink' => 'მუდმივი ბმული', |
214 | | -'print' => 'ბეჭდვა', |
215 | | -'edit' => 'რედაქტირება', |
216 | | -'editthispage' => 'ამ გვერდის რედაქტირება', |
217 | | -'delete' => 'წაშლა', |
218 | | -'deletethispage' => 'ამ გვერდის წაშლა', |
219 | | -'undelete_short' => '$1 ცვლილების აღდგენა', |
220 | | -'protect' => 'დაცვა', |
221 | | -#TODO: 'protectthispage' => 'Protect this page', |
222 | | -'unprotect' => 'დაცვის მოხსნა', |
223 | | -'unprotectthispage' => 'გვერდის დაცვის მოხსნა', |
224 | | -'newpage' => 'ახალი გვერდი', |
225 | | -'talkpage' => 'განიხილეთ ეს გვერდი', |
226 | | -'specialpage' => 'სპეციალური გვერდი', |
227 | | -#TODO: 'personaltools' => 'Personal tools', |
228 | | -'postcomment' => 'დაურთეთ კომენტარი', |
| 217 | +'badaccess' => 'აკრძალული მოქმედება', |
229 | 218 | |
230 | | -'articlepage' => 'სტატიის ნახვა', |
231 | | -'talk' => 'განხილვა', |
232 | | -#TODO: 'views' => 'Views', |
233 | | -'toolbox' => 'ხელსაწყოები', |
234 | | -'userpage' => 'მომხმარებლის გვერდის ხილვა', |
235 | | -'projectpage' => 'პროექტის გვერდის ხილვა', |
236 | | -'imagepage' => 'სურათის გვერდის ნახვა', |
237 | | -#TODO: 'mediawikipage' => 'View message page', |
238 | | -#TODO: #'templatepage' => 'View template page', |
239 | | -#TODO: 'viewhelppage' => 'View help page', |
240 | | -'categorypage' => 'კატეგორიის გვერდის ხილვა', |
241 | | -#TODO: 'viewtalkpage' => 'View discussion', |
242 | | -'otherlanguages' => 'სხვა ენებზე', |
243 | | -#TODO: 'redirectedfrom' => '(Redirected from $1)', |
244 | | -'autoredircomment' => 'გადამისამართება [[$1]]-ზე', |
245 | | -'redirectpagesub' => 'გადამისამართების გვერდი', |
246 | | -'lastmodifiedat' => 'ეს გვერდი ბოლოს განახლდა $2, $1.', //$1 date, $2 time |
247 | | -#TODO: 'viewcount' => 'This page has been accessed {{plural:$1|one time|$1 times}}.', |
248 | | -#TODO: 'copyright' => 'Content is available under $1.', |
249 | | -#TODO: 'protectedpage' => 'Protected page', |
250 | | -#TODO: 'jumpto' => 'Jump to:', |
251 | | -'jumptonavigation' => 'ნავიგაცია', |
252 | | -'jumptosearch' => 'ძიება', |
253 | | - |
254 | | -'badaccess' => 'აკრძალული მოქმედება', |
255 | | -#'badaccess-group0' => 'You are not allowed to execute the action you have requested.', |
256 | | -#'badaccess-group1' => 'The action you have requested is limited to users in the group $1.', |
257 | | -#'badaccess-group2' => 'The action you have requested is limited to users in one of the groups $1.', |
258 | | -#'badaccess-groups' => 'The action you have requested is limited to users in one of the groups $1.', |
259 | | - |
260 | | -#'versionrequired' => 'Version $1 of MediaWiki required', |
261 | | -#'versionrequiredtext' => 'Version $1 of MediaWiki is required to use this page. See [[Special:Version]]', |
262 | | - |
263 | | -#DONT: 'widthheight' => '$1×$2', |
264 | | -#'ok' => 'OK', |
265 | | -#'sitetitle' => '{{SITENAME}}', |
266 | | -#'pagetitle' => '$1 - {{SITENAME}}', |
267 | | -#'sitesubtitle' => '', |
268 | | -#'retrievedfrom' => 'Retrieved from "$1"', |
269 | | -'youhavenewmessages' => 'თქვენ გაქვთ $1 ($2).', |
270 | | -'newmessageslink' => 'ახალი შეტყობინებები', |
| 219 | +'youhavenewmessages' => 'თქვენ გაქვთ $1 ($2).', |
| 220 | +'newmessageslink' => 'ახალი შეტყობინებები', |
271 | 221 | 'newmessagesdifflink' => 'განსხვავება უკანასკნელ მდგომარეობას შორის', |
272 | | -'editsection'=>'რედაქტირება', |
273 | | -'editold'=>'რედაქტირება', |
274 | | -'editsectionhint' => 'სექციის რედაქტირება: $1', |
275 | | -'toc' => 'სარჩევი', |
276 | | -'showtoc' => 'ჩვენება', |
277 | | -'hidetoc' => 'დამალვა', |
278 | | -'thisisdeleted' => 'გსურთ განიხილოთ ან აღადგინოთ $1?', |
279 | | -'viewdeleted' => 'იხილე $1?', |
280 | | -'restorelink' => '{{PLURAL:$1|ერთი წაშლილი რედაქტირება|$1 წაშლილი რედაქტირება}}', |
281 | | -#'feedlinks' => 'Feed:', |
282 | | -#'feed-invalid' => 'Invalid subscription feed type.', |
283 | | -#'sitenotice' => '-', # the equivalent to wgSiteNotice |
284 | | -#'anonnotice' => '-', |
| 222 | +'editsection' => 'რედაქტირება', |
| 223 | +'editold' => 'რედაქტირება', |
| 224 | +'editsectionhint' => 'სექციის რედაქტირება: $1', |
| 225 | +'toc' => 'სარჩევი', |
| 226 | +'showtoc' => 'ჩვენება', |
| 227 | +'hidetoc' => 'დამალვა', |
| 228 | +'thisisdeleted' => 'გსურთ განიხილოთ ან აღადგინოთ $1?', |
| 229 | +'viewdeleted' => 'იხილე $1?', |
| 230 | +'restorelink' => '{{PLURAL:$1|ერთი წაშლილი რედაქტირება|$1 წაშლილი რედაქტირება}}', |
285 | 231 | |
286 | 232 | # Short words for each namespace, by default used in the 'article' tab in monobook |
287 | | -'nstab-main' => 'სტატია', |
288 | | -'nstab-user' => 'მომხმარებლის გვერდი', |
289 | | -'nstab-media' => 'მედია', |
290 | | -'nstab-special' => 'სპეციალური', |
291 | | -'nstab-project' => 'პროექტის გვერდი', |
292 | | -'nstab-image' => 'ფაილი', |
| 233 | +'nstab-main' => 'სტატია', |
| 234 | +'nstab-user' => 'მომხმარებლის გვერდი', |
| 235 | +'nstab-media' => 'მედია', |
| 236 | +'nstab-special' => 'სპეციალური', |
| 237 | +'nstab-project' => 'პროექტის გვერდი', |
| 238 | +'nstab-image' => 'ფაილი', |
293 | 239 | 'nstab-mediawiki' => 'შეტყობინება', |
294 | | -'nstab-template' => 'თარგი', |
295 | | -'nstab-help' => 'დახმარება', |
296 | | -'nstab-category' => 'კატეგორია', |
| 240 | +'nstab-template' => 'თარგი', |
| 241 | +'nstab-help' => 'დახმარება', |
| 242 | +'nstab-category' => 'კატეგორია', |
297 | 243 | |
298 | | -# Main script and global functions |
299 | | - |
300 | | -# General errors |
301 | | - |
302 | 244 | # Login and logout pages |
| 245 | +'login' => 'შესვლა', |
| 246 | +'userlogin' => 'შესვლა / ანგარიშის გახსნა', |
| 247 | +'logout' => 'გასვლა', |
| 248 | +'userlogout' => 'გასვლა', |
303 | 249 | |
304 | | -# Edit page toolbar |
305 | | - |
306 | | -# Edit pages |
307 | | - |
308 | | -# History pages |
309 | | - |
310 | | -# Revision deletion |
311 | | - |
312 | 250 | # Diffs |
313 | | -'difference' => '(სხვაობა ვერსიებს შორის)', |
314 | | -#TODO: 'loadingrev' => 'loading revision for diff', |
315 | | -'lineno' => "ხაზი $1:", |
316 | | -'editcurrent' => 'ამ გვერდის ამჟამინდელი ვერსიის რედაქტირება', |
317 | | -#TODO: 'selectnewerversionfordiff' => 'Select a newer version for comparison', |
318 | | -#TODO: 'selectolderversionfordiff' => 'Select an older version for comparison', |
| 251 | +'difference' => '(სხვაობა ვერსიებს შორის)', |
| 252 | +'lineno' => 'ხაზი $1:', |
| 253 | +'editcurrent' => 'ამ გვერდის ამჟამინდელი ვერსიის რედაქტირება', |
319 | 254 | 'compareselectedversions' => 'არჩეული ვერსიების შედარება', |
320 | 255 | |
321 | 256 | # Search results |
322 | | -# |
323 | | -#TODO: 'searchresults' => 'Search results', |
324 | | -#TODO: 'searchresulttext' => "For more information about searching {{SITENAME}}, see [[{{MediaWiki:helppage}}|{{int:help}}]].", |
325 | | -#TODO: 'searchsubtitle' => "You searched for '''[[:$1]]'''", |
326 | | -#TODO: 'searchsubtitleinvalid' => "You searched for '''$1'''", |
327 | | -#TODO: 'badquery' => 'Badly formed search query', |
328 | | -/*#TODO: 'badquerytext' => 'We could not process your query. |
329 | | -This is probably because you have attempted to search for a |
330 | | -word fewer than three letters long, which is not yet supported. |
331 | | -It could also be that you have mistyped the expression, for |
332 | | -example "fish and and scales". |
333 | | -Please try another query.',*/ |
334 | | -/*#TODO: 'matchtotals' => "The query \"$1\" matched $2 page titles |
335 | | -and the text of $3 pages.",*/ |
336 | | -#TODO: 'noexactmatch' => "'''There is no page titled \"$1\".''' You can [[:$1|create this page]].", |
337 | | -#TODO: 'titlematches' => 'Article title matches', |
338 | | -#TODO: 'notitlematches' => 'No page title matches', |
339 | | -#TODO: 'textmatches' => 'Page text matches', |
340 | | -#TODO: 'notextmatches' => 'No page text matches', |
341 | | -#TODO: 'prevn' => "previous $1", |
342 | | -#TODO: 'nextn' => "next $1", |
343 | | -#TODO: 'viewprevnext' => "View ($1) ($2) ($3).", |
344 | | -#TODO: 'showingresults' => "Showing below up to <b>$1</b> results starting with #<b>$2</b>.", |
345 | | -#TODO: 'showingresultsnum' => "Showing below <b>$3</b> results starting with #<b>$2</b>.", |
346 | | -/*#TODO: 'nonefound' => "'''Note''': Unsuccessful searches are |
347 | | -often caused by searching for common words like \"have\" and \"from\", |
348 | | -which are not indexed, or by specifying more than one search term (only pages |
349 | | -containing all of the search terms will appear in the result).",*/ |
350 | | -#TODO: 'powersearch' => 'Search', |
351 | | -#TODO: 'powersearchtext' => "Search in namespaces:<br />$1<br />$2 List redirects<br />Search for $3 $9", |
352 | | -#TODO: 'searchdisabled' => '{{SITENAME}} search is disabled. You can search via Google in the meantime. Note that their indexes of {{SITENAME}} content may be out of date.', |
353 | | - |
354 | | -/*#TODO: 'googlesearch' => ' |
355 | | -<form method="get" action="http://www.google.com/search" id="googlesearch"> |
356 | | - <input type="hidden" name="domains" value="{{SERVER}}" /> |
357 | | - <input type="hidden" name="num" value="50" /> |
358 | | - <input type="hidden" name="ie" value="$2" /> |
359 | | - <input type="hidden" name="oe" value="$2" /> |
360 | | - |
361 | | - <input type="text" name="q" size="31" maxlength="255" value="$1" /> |
362 | | - <input type="submit" name="btnG" value="$3" /> |
363 | | - <div> |
364 | | - <input type="radio" name="sitesearch" id="gwiki" value="{{SERVER}}" checked="checked" /><label for="gwiki">{{SITENAME}}</label> |
365 | | - <input type="radio" name="sitesearch" id="gWWW" value="" /><label for="gWWW">WWW</label> |
366 | | - </div> |
367 | | -</form>',*/ |
368 | 257 | 'blanknamespace' => '(მთავარი)', |
369 | 258 | |
370 | 259 | # Preferences page |
371 | | -'preferences' => 'კონფიგურაცია', |
372 | | -'mypreferences' => 'ჩემი კონფიგურაცია', |
373 | | -#TODO: 'prefsnologin' => 'Not logged in', |
374 | | -#TODO: 'prefsnologintext' => "You must be [[Special:Userlogin|logged in]] to set user preferences.", |
375 | | -#TODO: 'prefsreset' => 'Preferences have been reset from storage.', |
376 | | -'qbsettings' => 'სწრაფი ზოლი', |
377 | | -'changepassword' => 'პაროლის შეცვლა', |
378 | | -#TODO: 'skin' => 'Skin', |
379 | | -#TODO: 'math' => 'Math', |
380 | | -'dateformat' => 'თარიღის ფორმატი', |
381 | | -#TODO: 'datedefault' => 'No preference', |
382 | | -'datetime' => 'თარიღი და დრო', |
383 | | -#TODO: 'math_failure' => 'Failed to parse', |
384 | | -#TODO: 'math_unknown_error' => 'unknown error', |
385 | | -#TODO: 'math_unknown_function' => 'unknown function', |
386 | | -#TODO: 'math_lexing_error' => 'lexing error', |
387 | | -#TODO: 'math_syntax_error' => 'syntax error', |
388 | | -#TODO: 'math_image_error' => 'PNG conversion failed; check for correct installation of latex, dvips, gs, and convert', |
389 | | -#TODO: 'math_bad_tmpdir' => 'Can\'t write to or create math temp directory', |
390 | | -#TODO: 'math_bad_output' => 'Can\'t write to or create math output directory', |
391 | | -#TODO: 'math_notexvc' => 'Missing texvc executable; please see math/README to configure.', |
392 | | -'prefs-personal' => 'მომხმარებლის მონაცემები', |
393 | | -'prefs-rc' => 'ბოლო ცვლილებები', |
394 | | -'prefs-watchlist' => 'კონტროლის სია', |
395 | | -#TODO: 'prefs-watchlist-days' => 'Number of days to show in watchlist:', |
396 | | -#TODO: 'prefs-watchlist-edits' => 'Number of edits to show in expanded watchlist:', |
397 | | -#TODO: 'prefs-misc' => 'Misc', |
398 | | -'saveprefs' => 'შენახვა', |
399 | | -'resetprefs' => 'გადატვირთვა', |
400 | | -'oldpassword' => 'ძველი პაროლი:', |
401 | | -'newpassword' => 'ახალი პაროლი:', |
402 | | -#TODO: 'retypenew' => 'Retype new password:', |
403 | | -'textboxsize' => 'რედაქტირება', |
404 | | -'rows' => 'რიგები:', |
405 | | -'columns' => 'სვეტები:', |
| 260 | +'preferences' => 'კონფიგურაცია', |
| 261 | +'mypreferences' => 'ჩემი კონფიგურაცია', |
| 262 | +'qbsettings' => 'სწრაფი ზოლი', |
| 263 | +'changepassword' => 'პაროლის შეცვლა', |
| 264 | +'dateformat' => 'თარიღის ფორმატი', |
| 265 | +'datetime' => 'თარიღი და დრო', |
| 266 | +'prefs-personal' => 'მომხმარებლის მონაცემები', |
| 267 | +'prefs-rc' => 'ბოლო ცვლილებები', |
| 268 | +'prefs-watchlist' => 'კონტროლის სია', |
| 269 | +'saveprefs' => 'შენახვა', |
| 270 | +'resetprefs' => 'გადატვირთვა', |
| 271 | +'oldpassword' => 'ძველი პაროლი:', |
| 272 | +'newpassword' => 'ახალი პაროლი:', |
| 273 | +'textboxsize' => 'რედაქტირება', |
| 274 | +'rows' => 'რიგები:', |
| 275 | +'columns' => 'სვეტები:', |
406 | 276 | 'searchresultshead' => 'ძიება', |
407 | | -#TODO: 'resultsperpage' => 'Hits per page:', |
408 | | -'contextlines' => 'სტრიქონები შედეგის მიხედვით:', |
409 | | -'contextchars' => 'კონტექსტი სტრიქონების მიხედვით:', |
410 | | -#TODO: 'stubthreshold' => 'Threshold for stub display:', |
411 | | -#TODO: 'recentchangescount' => 'Titles in recent changes:', |
412 | | -'savedprefs' => 'თქვენს მიერ შერჩეული პარამეტრები დამახსოვრებულია.', |
413 | | -#TODO: 'timezonelegend' => 'Time zone', |
414 | | -#TODO: 'timezonetext' => 'The number of hours your local time differs from server time (UTC).', |
415 | | -'localtime' => 'ლოკალური დრო', |
416 | | -#TODO: 'timezoneoffset' => 'Offset¹', |
417 | | -#TODO: 'servertime' => 'Server time', |
418 | | -'guesstimezone' => 'ბრაუზერიდან შევსება', |
419 | | -'allowemail' => 'შესაძლებელია ელ. წერილების მიღება სხვა მომხმარებლებისაგან', |
420 | | -'defaultns' => 'სტანდარტული ძიება ამ სახელთა სივრცეებში:', |
421 | | -'default' => 'სტანდარტული', |
422 | | -'files' => 'ფაილები', |
| 277 | +'contextlines' => 'სტრიქონები შედეგის მიხედვით:', |
| 278 | +'contextchars' => 'კონტექსტი სტრიქონების მიხედვით:', |
| 279 | +'savedprefs' => 'თქვენს მიერ შერჩეული პარამეტრები დამახსოვრებულია.', |
| 280 | +'localtime' => 'ლოკალური დრო', |
| 281 | +'guesstimezone' => 'ბრაუზერიდან შევსება', |
| 282 | +'allowemail' => 'შესაძლებელია ელ. წერილების მიღება სხვა მომხმარებლებისაგან', |
| 283 | +'defaultns' => 'სტანდარტული ძიება ამ სახელთა სივრცეებში:', |
| 284 | +'default' => 'სტანდარტული', |
| 285 | +'files' => 'ფაილები', |
423 | 286 | |
424 | | -# User rights |
425 | | - |
426 | 287 | # Groups |
427 | | -'group' => 'ჯგუფი:', |
428 | | -'group-bot' => 'რობოტები', |
429 | | -'group-sysop' => 'ადმინისტრატორები', |
430 | | -'group-bureaucrat' => 'ბიუროკრატები', |
431 | | -'group-all' => '(ყველა)', |
| 288 | +'group' => 'ჯგუფი:', |
| 289 | +'group-bot' => 'ბოტები', |
| 290 | +'group-sysop' => 'ადმინისტრატორები', |
| 291 | +'group-bureaucrat' => 'ბიუროკრატები', |
| 292 | +'group-all' => '(ყველა)', |
432 | 293 | |
433 | | -'group-bot-member' => 'რობოტი', |
| 294 | +'group-bot-member' => 'ბოტი', |
434 | 295 | 'group-sysop-member' => 'ადმინისტრატორი', |
435 | 296 | 'group-bureaucrat-member' => 'ბიუროკრატი', |
436 | 297 | |
437 | | -'grouppage-bot' => '{{ns:project}}:რობოტები', |
438 | | -'grouppage-sysop' => '{{ns:project}}:ადმინისტრატორები', |
| 298 | +'grouppage-bot' => '{{ns:project}}:ბოტები', |
| 299 | +'grouppage-sysop' => '{{ns:project}}:ადმინისტრატორები', |
439 | 300 | 'grouppage-bureaucrat' => '{{ns:project}}:ბიუროკრატები', |
440 | 301 | |
441 | 302 | # Recent changes |
442 | | -'changes' => 'ცვლილებები', |
443 | | -'recentchanges' => 'ბოლო ცვლილებები', |
444 | | -#DONT: 'recentchanges-url' => 'Special:Recentchanges', |
445 | | -#TODO: 'recentchangestext' => 'Track the most recent changes to the wiki on this page.', |
446 | | -#TODO: 'rcnote' => "Below are the last <strong>$1</strong> changes in the last <strong>$2</strong> days, as of $3.", |
447 | | -#TODO: 'rcnotefrom' => "Below are the changes since <b>$2</b> (up to <b>$1</b> shown).", |
448 | | -'rclistfrom' => "ახალი ცვლილებების ჩვენება დაწყებული $1-დან", |
| 303 | +'nchanges' => '$1 ცვლილები', |
| 304 | +'recentchanges' => 'ბოლო ცვლილებები', |
| 305 | +'rclistfrom' => 'ახალი ცვლილებების ჩვენება დაწყებული $1-დან', |
449 | 306 | 'rcshowhideminor' => 'მცირე რედაქტირების $1', |
450 | | -'rcshowhidebots' => 'რობოტების $1', |
451 | | -'rcshowhideliu' => 'რეგისტრირებული მომხმარებლების $1', |
| 307 | +'rcshowhidebots' => 'ბოტების $1', |
| 308 | +'rcshowhideliu' => 'რეგისტრირებული მომხმარებლების $1', |
452 | 309 | 'rcshowhideanons' => 'ანონიმური მომხმარებლების $1', |
453 | | -#TODO: 'rcshowhidepatr' => '$1 patrolled edits', |
454 | | -'rcshowhidemine' => 'ჩემი რედაქტირების $1', |
455 | | -'rclinks' => "ბოლო $1 ცვლილების ჩვენება უკანასკნელი $2 დღის მანძილზე<br />$3", |
456 | | -'diff' => 'განსხ.', |
457 | | -'hist' => 'ისტ.', |
458 | | -'hide' => 'დამალვა', |
459 | | -'show' => 'ჩვენება', |
| 310 | +'rcshowhidemine' => 'ჩემი რედაქტირების $1', |
| 311 | +'rclinks' => 'ბოლო $1 ცვლილების ჩვენება უკანასკნელი $2 დღის მანძილზე<br />$3', |
| 312 | +'diff' => 'განსხ.', |
| 313 | +'hist' => 'ისტ.', |
| 314 | +'hide' => 'დამალვა', |
| 315 | +'show' => 'ჩვენება', |
460 | 316 | 'minoreditletter' => 'მ', |
461 | | -'newpageletter' => 'ა', |
462 | | -'boteditletter' => 'რ', |
463 | | -'sectionlink' => '→', |
464 | | -#TODO: 'number_of_watching_users_RCview' => '[$1]', |
465 | | -#TODO: 'number_of_watching_users_pageview' => '[$1 watching user/s]', |
466 | | -#TODO: 'rc_categories' => 'Limit to categories (separate with "|")', |
467 | | -#TODO: 'rc_categories_any' => 'Any', |
| 317 | +'newpageletter' => 'ა', |
| 318 | +'boteditletter' => 'ბ', |
| 319 | +'sectionlink' => '→', |
468 | 320 | |
| 321 | +# Recent changes linked |
| 322 | +'recentchangeslinked' => 'დაკავშირებული ცვლილებები', |
| 323 | + |
469 | 324 | # Upload |
| 325 | +'upload' => 'ფაილის დამატება', |
| 326 | +'uploadbtn' => 'ფაილის დამატება', |
470 | 327 | |
471 | 328 | # Image list |
472 | | -'imagelist' => 'ფაილების სია', |
473 | | -'imagelisttext' => "ქვემოთ მოცემულია '''$1''' ფაილის სია დახარისხებული მომხმარებლის $2 მიერ.", |
474 | | -'imagelistforuser' => "აქ მხოლოდ ნაჩვენებია მომხმარებლის $1 მიერ ჩატვირთული სურათები.", |
475 | | -'getimagelist' => 'ფაილთა სიის ჩამოტვირთვა', |
476 | | -'ilsubmit' => 'ძიება', |
477 | | -#TODO: 'showlast' => 'Show last $1 files sorted $2.', |
478 | | -'byname' => 'სახელით', |
479 | | -'bydate' => 'თარიღით', |
480 | | -'bysize' => 'ზომით', |
481 | | -'imgdelete' => 'წაშ.', |
482 | | -'imgdesc' => 'აღწ.', |
483 | | -'imgfile' => 'ფაილი', |
484 | | -#TODO: 'imglegend' => 'Legend: (desc) = show/edit file description.', |
485 | | -'imghistory' => 'ფაილის ისტორია', |
486 | | -#TODO: 'revertimg' => 'rev', |
487 | | -'deleteimg' => 'წაშ.', |
488 | | -#TODO: 'deleteimgcompletely' => 'Delete all revisions of this file', |
489 | | -/*TODO: 'imghistlegend' => 'Legend: (cur) = this is the current file, (del) = delete |
490 | | -this old version, (rev) = revert to this old version. |
491 | | -<br /><i>Click on date to see the file uploaded on that date</i>.',*/ |
492 | | -'imagelinks' => 'ბმულები', |
493 | | -'linkstoimage' => 'ამ ფაილზე ბმული მოცემულია შემდეგ გვერდებზე:', |
494 | | -'nolinkstoimage' => 'არ არსებობს ამ ფაილთან დაკავშირებული გვერდები.', |
495 | | -#TODO: 'sharedupload' => 'This file is a shared upload and may be used by other projects.', |
496 | | -'shareduploadwiki' => 'გთხოვთ, იხილოთ $1 შემდგომი ინფორმაციის მისაღებად.', |
497 | | -#TODO: 'shareduploadwiki-linktext' => 'file description page', |
498 | | -#DONT: 'shareddescriptionfollows' => '-', |
499 | | -'noimage' => 'ამ სახელის მქონე ფაილი არ არსებობს, თქვენ შეგიძლიათ $1.', |
500 | | -'noimage-linktext' => 'ფაილის ატვირთვა', |
| 329 | +'imagelist' => 'ფაილების სია', |
| 330 | +'imagelisttext' => "ქვემოთ მოცემულია '''$1''' ფაილის სია დახარისხებული მომხმარებლის $2 მიერ.", |
| 331 | +'imagelistforuser' => 'აქ მხოლოდ ნაჩვენებია მომხმარებლის $1 მიერ ჩატვირთული სურათები.', |
| 332 | +'getimagelist' => 'ფაილთა სიის ჩამოტვირთვა', |
| 333 | +'ilsubmit' => 'ძიება', |
| 334 | +'byname' => 'სახელით', |
| 335 | +'bydate' => 'თარიღით', |
| 336 | +'bysize' => 'ზომით', |
| 337 | +'imgdelete' => 'წაშ.', |
| 338 | +'imgdesc' => 'აღწ.', |
| 339 | +'imgfile' => 'ფაილი', |
| 340 | +'imghistory' => 'ფაილის ისტორია', |
| 341 | +'deleteimg' => 'წაშ.', |
| 342 | +'imagelinks' => 'ბმულები', |
| 343 | +'linkstoimage' => 'ამ ფაილზე ბმული მოცემულია შემდეგ გვერდებზე:', |
| 344 | +'nolinkstoimage' => 'არ არსებობს ამ ფაილთან დაკავშირებული გვერდები.', |
| 345 | +'shareduploadwiki' => 'გთხოვთ, იხილოთ $1 შემდგომი ინფორმაციის მისაღებად.', |
| 346 | +'noimage' => 'ამ სახელის მქონე ფაილი არ არსებობს, თქვენ შეგიძლიათ $1.', |
| 347 | +'noimage-linktext' => 'ფაილის ატვირთვა', |
501 | 348 | 'uploadnewversion-linktext' => 'ამ ფაილის ახალი ვერსიის ატვირთვა', |
502 | | -'imagelist_date' => 'თარიღი', |
503 | | -'imagelist_name' => 'სახელი', |
504 | | -'imagelist_user' => 'მომხმარებელი', |
505 | | -'imagelist_size' => 'ზომა (ბაიტები)', |
506 | | -'imagelist_description' => 'აღწერილობა', |
507 | | -'imagelist_search_for' => 'ძიება სურათის სახელის მიხედვით:', |
| 349 | +'imagelist_date' => 'თარიღი', |
| 350 | +'imagelist_name' => 'სახელი', |
| 351 | +'imagelist_user' => 'მომხმარებელი', |
| 352 | +'imagelist_size' => 'ზომა (ბაიტები)', |
| 353 | +'imagelist_description' => 'აღწერილობა', |
| 354 | +'imagelist_search_for' => 'ძიება სურათის სახელის მიხედვით:', |
508 | 355 | |
509 | | -# Mime search |
510 | | - |
511 | | -# Unwatchedpages |
512 | | - |
513 | | -# List redirects |
514 | | - |
515 | | -# Unused templates |
516 | | - |
517 | 356 | # Random redirect |
518 | 357 | 'randomredirect' => 'ნებისმიერი გადამისამართება', |
519 | 358 | |
520 | 359 | # Statistics |
| 360 | +'statistics' => 'სტატისტიკა', |
521 | 361 | |
522 | 362 | # Miscellaneous special pages |
523 | | -# |
524 | | -'nbytes' => '$1 ბაიტი', |
525 | | -'ncategories' => '$1 კატეგორია', |
526 | | -'nlinks' => '$1 ბმული', |
527 | | -'nmembers' => '$1 წევრი', |
528 | | -#TODO: 'nrevisions' => '$1 {{PLURAL:$1|revision|revisions}}', |
529 | | -#TODO: 'nviews' => '$1 {{PLURAL:$1|view|views}}', |
530 | | -#TODO: 'specialpage-empty' => 'This page is empty.', |
531 | | -#TODO: 'lonelypages' => 'Orphaned pages', |
532 | | -#'lonelypages-summary' => '', |
533 | | -#TODO: 'lonelypagestext' => 'The following pages are not linked from other pages in this wiki.', |
534 | | -'uncategorizedpages' => 'გვერდები კატეგორიის გარეშე', |
535 | | -#'uncategorizedpages-summary' => '', |
536 | | -'uncategorizedcategories' => 'კატეგორიები კატეგორიის გარეშე', |
537 | | -#'uncategorizedcategories-summary' => '', |
538 | | -'uncategorizedimages' => 'სურათები კატეგორიის გარეშე', |
539 | | -#'uncategorizedimages-summary' => '', |
540 | | -'unusedcategories' => 'გამოუყენებელი კატეგორიები', |
541 | | -'unusedimages' => 'გამოუყენებელი სურათები', |
542 | | -'popularpages' => 'პოპულარული გვერდები', |
543 | | -#'popularpages-summary' => '', |
544 | | -'wantedcategories' => 'მოთხოვნილი კატეგორიები', |
545 | | -#'wantedcategories-summary' => '', |
546 | | -'wantedpages' => 'მოთხოვნილი გვერდები', |
547 | | -#'wantedpages-summary' => '', |
548 | | -#TODO: 'mostlinked' => 'Most linked to pages', |
549 | | -#'mostlinked-summary' => '', |
550 | | -#TODO: 'mostlinkedcategories' => 'Most linked to categories', |
551 | | -#'mostlinkedcategories-summary' => '', |
552 | | -'mostcategories' => 'ყველაზე მეტი კატეგორიის მქონე სტატიები', |
553 | | -#'mostcategories-summary' => '', |
554 | | -#TODO: 'mostimages' => 'Most linked to images', |
555 | | -#'mostimages-summary' => '', |
556 | | -'mostrevisions' => 'ყველაზე მეტად რედაქტირებული სტატიები', |
557 | | -#'mostrevisions-summary' => '', |
558 | | -'allpages' => 'ყველა გვერდი', |
559 | | -#'allpages-summary' => '', |
560 | | -#TODO: 'prefixindex' => 'Prefix index', |
561 | | -#'prefixindex-summary' => '', |
562 | | -'randompage' => 'ნებისმიერი გვერდი', |
563 | | -#DONT: 'randompage-url'=> 'სპეციალური:Random', |
564 | | -'shortpages' => 'მოკლე გვერდები', |
565 | | -#'shortpages-summary' => '', |
566 | | -'longpages' => 'გრძელი გვერდები', |
567 | | -#'longpages-summary' => '', |
568 | | -'deadendpages' => 'ჩიხის გვერდები', |
569 | | -#'deadendpages-summary' => '', |
570 | | -#TODO: 'deadendpagestext' => 'The following pages do not link to other pages in this wiki.', |
571 | | -#TODO: 'protectedpages' => 'Protected pages', |
572 | | -#'protectedpages-summary' => '', |
573 | | -#TODO: 'protectedpagestext' => 'The following pages are protected from moving or editing', |
574 | | -#TODO: 'protectedpagesempty' => 'No pages are currently protected', |
575 | | -'listusers' => 'მომხმარებლების სია', |
576 | | -#'listusers-summary' => '', |
577 | | -'specialpages' => 'სპეციალური გვერდები', |
578 | | -#'specialpages-summary' => '', |
579 | | -'spheading' => 'სპეციალური გვერდები ყველა მომხმარებლისათვის', |
580 | | -'restrictedpheading' => 'შეზღუდული სპეციალური გვერდები', |
581 | | -'recentchangeslinked' => 'დაკავშირებული ცვლილებები', |
582 | | -#TODO: 'rclsub' => "(to pages linked from \"$1\")", |
583 | | -'newpages' => 'ახალი გვერდები', |
584 | | -#'newpages-summary' => '', |
585 | | -'newpages-username' => 'მომხმარებლის სახელი:', |
586 | | -'ancientpages' => 'ხანდაზმული გვერდები', |
587 | | -#'ancientpages-summary' => '', |
588 | | -'intl' => 'ენათშორისი ბმულები', |
589 | | -'move' => 'გადატანა', |
590 | | -'movethispage' => 'ამ გვერდის გადატანა', |
591 | | -'unusedimagestext' => '<p>გთხოვთ გაითვალისწინოთ, რომ შეიძლება სხვა ვიკი ზოგიერთ ამ გამოსახულებას იყენებს.</p>', |
592 | | -#TODO: 'unusedcategoriestext' => 'The following category pages exist although no other article or category make use of them.', |
| 363 | +'nbytes' => '$1 ბაიტი', |
| 364 | +'ncategories' => '$1 კატეგორია', |
| 365 | +'nlinks' => '$1 ბმული', |
| 366 | +'nmembers' => '$1 წევრი', |
| 367 | +'uncategorizedpages' => 'გვერდები კატეგორიის გარეშე', |
| 368 | +'uncategorizedcategories' => 'კატეგორიები კატეგორიის გარეშე', |
| 369 | +'uncategorizedimages' => 'სურათები კატეგორიის გარეშე', |
| 370 | +'unusedcategories' => 'გამოუყენებელი კატეგორიები', |
| 371 | +'unusedimages' => 'გამოუყენებელი სურათები', |
| 372 | +'popularpages' => 'პოპულარული გვერდები', |
| 373 | +'wantedcategories' => 'მოთხოვნილი კატეგორიები', |
| 374 | +'wantedpages' => 'მოთხოვნილი გვერდები', |
| 375 | +'mostcategories' => 'ყველაზე მეტი კატეგორიის მქონე სტატიები', |
| 376 | +'mostrevisions' => 'ყველაზე მეტად რედაქტირებული სტატიები', |
| 377 | +'allpages' => 'ყველა გვერდი', |
| 378 | +'randompage' => 'ნებისმიერი გვერდი', |
| 379 | +'shortpages' => 'მოკლე გვერდები', |
| 380 | +'longpages' => 'გრძელი გვერდები', |
| 381 | +'deadendpages' => 'ჩიხის გვერდები', |
| 382 | +'listusers' => 'მომხმარებლების სია', |
| 383 | +'specialpages' => 'სპეციალური გვერდები', |
| 384 | +'spheading' => 'სპეციალური გვერდები ყველა მომხმარებლისათვის', |
| 385 | +'restrictedpheading' => 'შეზღუდული სპეციალური გვერდები', |
| 386 | +'newpages' => 'ახალი გვერდები', |
| 387 | +'newpages-username' => 'მომხმარებლის სახელი:', |
| 388 | +'ancientpages' => 'ხანდაზმული გვერდები', |
| 389 | +'intl' => 'ენათშორისი ბმულები', |
| 390 | +'move' => 'გადატანა', |
| 391 | +'movethispage' => 'ამ გვერდის გადატანა', |
| 392 | +'unusedimagestext' => '<p>გთხოვთ გაითვალისწინოთ, რომ შეიძლება სხვა ვიკი ზოგიერთ ამ გამოსახულებას იყენებს.</p>', |
593 | 393 | |
| 394 | +# Special:Log |
| 395 | +'specialloguserlabel' => 'მომხმარებელი:', |
| 396 | +'speciallogtitlelabel' => 'სათაური:', |
| 397 | + |
594 | 398 | # Special:Allpages |
595 | 399 | 'nextpage' => 'შემდეგი გვერდი ($1)', |
596 | 400 | 'prevpage' => 'წინა გვერდი ($1)', |
597 | | -'allpagesfrom' => 'გვერდების ჩვენება დაწყებული:', |
598 | | -'allarticles' => 'ყველა სტატია', |
599 | | -'allinnamespace' => 'ყველა გვერდი ($1 სახელთა სივრცეში)', |
600 | | -'allnotinnamespace' => 'ყველა გვერდი ($1 სახელთა სივრცის გარეშე)', |
601 | | -'allpagesprev' => 'წინა', |
602 | | -'allpagesnext' => 'შემდეგი', |
603 | | -'allpagessubmit' => 'ჩვენება', |
604 | | -'allpagesprefix' => 'ასახე გვერდები პრეფიქსით:', |
605 | | -'allpagesbadtitle' => 'მოცემული გვერდის სათაური არასწორია ან აქვს ინტერვიკი ან ნათშორისი პრეფიქსი. |
| 401 | +'allpagesfrom' => 'გვერდების ჩვენება დაწყებული:', |
| 402 | +'allarticles' => 'ყველა სტატია', |
| 403 | +'allinnamespace' => 'ყველა გვერდი ($1 სახელთა სივრცეში)', |
| 404 | +'allnotinnamespace' => 'ყველა გვერდი ($1 სახელთა სივრცის გარეშე)', |
| 405 | +'allpagesprev' => 'წინა', |
| 406 | +'allpagesnext' => 'შემდეგი', |
| 407 | +'allpagessubmit' => 'ჩვენება', |
| 408 | +'allpagesprefix' => 'ასახე გვერდები პრეფიქსით:', |
| 409 | +'allpagesbadtitle' => 'მოცემული გვერდის სათაური არასწორია ან აქვს ინტერვიკი ან ნათშორისი პრეფიქსი. |
606 | 410 | იგი შესაძლოა შეიცავდეს ერთ ან მეტ სიმბოლოს, რომელიც არ შეიძლება გამოყენებულ იქნას სათაურში.', |
607 | 411 | |
608 | | -# Special:Listusers |
609 | | - |
610 | | -# Email this user |
611 | | - |
612 | 412 | # Watchlist |
| 413 | +'watchlist' => 'ჩემი კონტროლის სია', |
| 414 | +'mywatchlist' => 'ჩემი კონტროლის სია', |
| 415 | +'watch' => 'კონტროლი', |
613 | 416 | |
614 | | -# Delete/protect/revert |
615 | | - |
616 | | -# restrictions (nouns) |
| 417 | +# Restrictions (nouns) |
617 | 418 | 'restriction-edit' => 'რედაქტირება', |
618 | | -#TODO: 'restriction-move' => 'Move', |
619 | 419 | |
620 | | -# restriction levels |
621 | | - |
622 | | - |
623 | 420 | # Undelete |
624 | | -'undelete' => 'აჩვენე წაშლილი გვერდები', |
625 | | -'undeletepage' => 'იხილეთ და აღადგინეთ წაშლილი გვერდები', |
626 | | -'viewdeletedpage' => 'იხილეთ წაშლილი გვერდები', |
627 | | -'undeletepagetext' => 'მომდევნო გვრდები წაშლილია, მაგრამ ჯერ კიდევ არქივშია და |
| 421 | +'undelete' => 'აჩვენე წაშლილი გვერდები', |
| 422 | +'undeletepage' => 'იხილეთ და აღადგინეთ წაშლილი გვერდები', |
| 423 | +'viewdeletedpage' => 'იხილეთ წაშლილი გვერდები', |
| 424 | +'undeletepagetext' => 'მომდევნო გვრდები წაშლილია, მაგრამ ჯერ კიდევ არქივშია და |
628 | 425 | შესაძლებელია აღდგენა. არქივი შესაძლებელია პერიოდულად გასუფთავდეს.', |
629 | | -'undeleteextrahelp' => "ამ მთლიანი გვერდის აღსადგენად, დატოვეთ ყველა მოსანიშნი უჯრა მოუნიშნავად და |
| 426 | +'undeleteextrahelp' => "ამ მთლიანი გვერდის აღსადგენად, დატოვეთ ყველა მოსანიშნი უჯრა მოუნიშნავად და |
630 | 427 | დააწკაპუნეთ '''''აღდგენა'''''. იმისათვის, რომ მოახდინოთ შერჩევითი აღდგენა მონიშნეთ უჯრები ჩასატარებელი |
631 | 428 | ვერსიების შესაბამისად და დააწკაპუნეთ '''''აღდგენა'''''. '''''გადატვირთვაზე''''' დაწკაპუნებით გაუქმდება ყველა |
632 | 429 | კომენტარის ველი და ყველა მოსანიშნი უჯრა.", |
633 | | -'undeletearticle' => 'აღადგინე წაშლილი გვერდი', |
634 | | -'undeleterevisions' => "$1 ვერსიები დაარქივებულია", |
635 | | -'undeletehistory' => 'თუ თქვენ აღადგენთ გვერდს, ყველა ვერსია აღდგება ისტორიაში. |
| 430 | +'undeleterevisions' => '$1 ვერსიები დაარქივებულია', |
| 431 | +'undeletehistory' => 'თუ თქვენ აღადგენთ გვერდს, ყველა ვერსია აღდგება ისტორიაში. |
636 | 432 | თუ ახალი გვერდი იგივე სახელით შეიქმნა მისი წაშლის შემდეგ, აღდგენილი |
637 | 433 | ვერსიები გამოჩნდება წინა ისტორიაში და მიმდინარე ვერსია |
638 | 434 | ავტომატურად არ ჩანაცვლდება.', |
639 | | -'undeletehistorynoadmin' => 'ეს სტატია წაშლილია. წაშლის მიზეზი ნაჩვენებია მოკლე ანოტაციაში ქვემოთ, იმ |
| 435 | +'undeletehistorynoadmin' => 'ეს სტატია წაშლილია. წაშლის მიზეზი ნაჩვენებია მოკლე ანოტაციაში ქვემოთ, იმ |
640 | 436 | მომხმარებელთა დეტალებთან ერთად ვინც რედაქტირება გაუკეთა ამ გვერდს წაშლის წინ. |
641 | 437 | იმ წაშლილი ტექსტების აქტუალური ვერსიები მიღწევადია მხოლოდ ადმინისტრატორებისათვის.', |
642 | | -#TODO: 'undelete-revision' => 'Deleted revision of $1 from $2:', |
643 | | -/*#TODO: 'undeleterevision-missing' => "Invalid or missing revision. You may have a bad link, or the |
644 | | -revision may have been restored or removed from the archive.",*/ |
645 | | -'undeletebtn' => 'აღდგენა', |
646 | | -'undeletereset' => 'გადატვირთეთ', |
647 | | -'undeletecomment' => 'კომენტარი:', |
648 | | -'undeletedarticle' => 'აღდგენილია "[[$1]]"', |
649 | | -'undeletedrevisions' => "$1 ვერსია აღდგენილია", |
650 | | -'undeletedrevisions-files' => "$1 ვერსია და $2 ფაილი აღდგენილია", |
651 | | -'undeletedfiles' => "$1 ფაილი აღდგენილია", |
652 | | -'cannotundelete' => 'აღდგენა ვერ შედგა; შესაძლოა უკვე ვიღაცამ აღადგინა ეს გვერდი.', |
653 | | -'undeletedpage' => "<big>'''$1 აღდგენილია'''</big> |
| 438 | +'undeletebtn' => 'აღდგენა', |
| 439 | +'undeletereset' => 'გადატვირთეთ', |
| 440 | +'undeletecomment' => 'კომენტარი:', |
| 441 | +'undeletedarticle' => 'აღდგენილია "[[$1]]"', |
| 442 | +'undeletedrevisions' => '$1 ვერსია აღდგენილია', |
| 443 | +'undeletedrevisions-files' => '$1 ვერსია და $2 ფაილი აღდგენილია', |
| 444 | +'undeletedfiles' => '$1 ფაილი აღდგენილია', |
| 445 | +'cannotundelete' => 'აღდგენა ვერ შედგა; შესაძლოა უკვე ვიღაცამ აღადგინა ეს გვერდი.', |
| 446 | +'undeletedpage' => "<big>'''$1 აღდგენილია'''</big> |
654 | 447 | |
655 | 448 | უკანასკნელი წაშლილთა და აღდგენის სია შეგიძლიათ ნახოთ [[Special:Log/delete|წაშლილთა სიაში]].", |
656 | | -#TODO: 'undelete-header' => 'See [[Special:Log/delete|the deletion log]] for recently deleted pages.', |
657 | | -#TODO: 'undelete-search-box' => 'Search deleted pages', |
658 | | -#TODO: 'undelete-search-prefix' => 'Show pages starting with:', |
659 | | -'undelete-search-submit' => 'ძიება', |
660 | | -#TODO: 'undelete-no-results' => 'No matching pages found in the deletion archive.', |
| 449 | +'undelete-search-submit' => 'ძიება', |
661 | 450 | |
662 | 451 | # Namespace form on various pages |
663 | 452 | 'namespace' => 'სახელთა სივრცე:', |
664 | | -'invert' => 'ყველა, მონიშნულის გარდა', |
| 453 | +'invert' => 'ყველა, მონიშნულის გარდა', |
665 | 454 | |
666 | 455 | # Contributions |
| 456 | +'contributions' => 'მომხმარებლის წვლილი', |
| 457 | +'mycontris' => 'ჩემი წვლილი', |
667 | 458 | |
668 | 459 | # What links here |
669 | | -# |
670 | | -'whatlinkshere' => 'სადაა მითითებული ეს გვერდი', |
671 | | -#'whatlinkshere-summary' => '', |
672 | | -#'whatlinkshere-barrow' => '<', |
| 460 | +'whatlinkshere' => 'სადაა მითითებული ეს გვერდი', |
673 | 461 | 'notargettitle' => 'სამიზნე არაა', |
674 | | -'notargettext' => 'თქვენ არ მიუთითეთ სამიზნე გვერდი ან მომხმარებელი |
| 462 | +'notargettext' => 'თქვენ არ მიუთითეთ სამიზნე გვერდი ან მომხმარებელი |
675 | 463 | ამ ფუნქციის შესასრულებლად.', |
676 | | -#TODO: 'linklistsub' => '(List of links)', |
677 | | -#TODO: 'linkshere' => "The following pages link to '''[[:$1]]''':", |
678 | | -'nolinkshere' => "'''[[:$1]]'''-ზე ბმული არ არის.", |
679 | | -#TODO: 'isredirect' => 'redirect page', |
680 | | -#TODO: 'istemplate' => 'inclusion', |
| 464 | +'nolinkshere' => "'''[[:$1]]'''-ზე ბმული არ არის.", |
681 | 465 | |
682 | | -# Block/unblock IP |
683 | | - |
684 | | -# Developer tools |
685 | | - |
686 | | -# Make sysop |
687 | | - |
688 | 466 | # Move page |
689 | | -# |
690 | | -'movepage' => 'გვერდის გადატანა', |
691 | | -/*TODO: 'movepagetext' => 'Using the form below will rename a page, moving all |
692 | | -of its history to the new name. |
693 | | -The old title will become a redirect page to the new title. |
694 | | -Links to the old page title will not be changed; be sure to |
695 | | -check for double or broken redirects. |
696 | | -You are responsible for making sure that links continue to |
697 | | -point where they are supposed to go. |
698 | | - |
699 | | -Note that the page will \'\'\'not\'\'\' be moved if there is already |
700 | | -a page at the new title, unless it is empty or a redirect and has no |
701 | | -past edit history. This means that you can rename a page back to where |
702 | | -it was just renamed from if you make a mistake, and you cannot overwrite |
703 | | -an existing page. |
704 | | - |
705 | | -<b>WARNING!</b> |
706 | | -This can be a drastic and unexpected change for a popular page; |
707 | | -please be sure you understand the consequences of this before |
708 | | -proceeding.',*/ |
709 | | -/*TODO: 'movepagetalktext' => 'The associated talk page will be automatically moved along with it \'\'\'unless:\'\'\' |
710 | | -*A non-empty talk page already exists under the new name, or |
711 | | -*You uncheck the box below. |
712 | | - |
713 | | -In those cases, you will have to move or merge the page manually if desired.',*/ |
714 | | -'movearticle' => 'გვერდის გადატანა', |
715 | | -'movenologin' => 'რეგისტრაცია ვერ გაიარა', |
716 | | -/*TODO: 'movenologintext' => "You must be a registered user and [[Special:Userlogin|logged in]] |
717 | | -to move a page.",*/ |
718 | | -'newtitle' => 'ახალი სათაური', |
719 | | -#TODO: 'move-watch' => 'Watch this page', |
720 | | -'movepagebtn' => 'გვერდის გადატანა', |
721 | | -#TODO: 'pagemovedsub' => 'Move succeeded', |
722 | | -'pagemovedtext' => "გვერდი \"[[$1]]\" გადავიდა \"[[$2]]\".", |
723 | | -'articleexists' => 'ამ დასახელების გვერდი უკვე არსებობს, |
| 467 | +'movepage' => 'გვერდის გადატანა', |
| 468 | +'movearticle' => 'გვერდის გადატანა', |
| 469 | +'movenologin' => 'რეგისტრაცია ვერ გაიარა', |
| 470 | +'newtitle' => 'ახალი სათაური', |
| 471 | +'move-watch' => 'ამ გვერდის კონტროლი', |
| 472 | +'movepagebtn' => 'გვერდის გადატანა', |
| 473 | +'pagemovedtext' => 'გვერდი "[[$1]]" გადავიდა "[[$2]]".', |
| 474 | +'articleexists' => 'ამ დასახელების გვერდი უკვე არსებობს, |
724 | 475 | ან თქვენს მიერ მითითებული დასახელება არასწორია. |
725 | 476 | თუ შეიძლება, მიუთითეთ სხვა სახელი.', |
726 | | -#TODO: 'talkexists' => "'''The page itself was moved successfully, but the talk page could not be moved because one already exists at the new title. Please merge them manually.'''", |
727 | | -'movedto' => 'გადატანილია', |
728 | | -'movetalk' => 'დაკავშირებული განხილვის გადატანა', |
729 | | -#TODO: 'talkpagemoved' => 'The corresponding talk page was also moved.', |
730 | | -#TODO: 'talkpagenotmoved' => 'The corresponding talk page was <strong>not</strong> moved.', |
731 | | -'1movedto2' => '[[$1]] გადატანილია [[$2]]-ზე', |
732 | | -'1movedto2_redir' => '[[$1]] გადატანილია [[$2]]-ზე გადამისამართებულ გვერდში', |
733 | | -'movelogpage' => 'გადატანის ჟურნალი', |
734 | | -#TODO: 'movelogpagetext' => 'Below is a list of page moved.', |
735 | | -'movereason' => 'მიზეზი', |
736 | | -#TODO: 'revertmove' => 'revert', |
737 | | -'delete_and_move' => 'წაშლა და გადატანა', |
738 | | -'delete_and_move_text' => |
739 | | -'==საჭიროა წაშლა== |
| 477 | +'movedto' => 'გადატანილია', |
| 478 | +'movetalk' => 'დაკავშირებული განხილვის გადატანა', |
| 479 | +'1movedto2' => '[[$1]] გადატანილია [[$2]]-ზე', |
| 480 | +'1movedto2_redir' => '[[$1]] გადატანილია [[$2]]-ზე გადამისამართებულ გვერდში', |
| 481 | +'movelogpage' => 'გადატანის ჟურნალი', |
| 482 | +'movereason' => 'მიზეზი', |
| 483 | +'delete_and_move' => 'წაშლა და გადატანა', |
| 484 | +'delete_and_move_text' => '==საჭიროა წაშლა== |
740 | 485 | |
741 | 486 | სტატია დასახელებით "[[$1]]" უკვე არსებობს. გსურთ მისი წაშლა გადატანისთვის ადგილის დასათმობად?', |
742 | 487 | 'delete_and_move_confirm' => 'დიახ, წაშალეთ ეს გვერდი', |
743 | | -'delete_and_move_reason' => 'წაშლილია გადატანისთვის ადგილის დასათმობად', |
744 | | -#TODO: 'selfmove' => "Source and destination titles are the same; can't move a page over itself.", |
745 | | -#TODO: 'immobile_namespace' => "Source or destination title is of a special type; cannot move pages from and into that namespace.",*/ |
| 488 | +'delete_and_move_reason' => 'წაშლილია გადატანისთვის ადგილის დასათმობად', |
746 | 489 | |
747 | | -# Export |
748 | | - |
749 | 490 | # Namespace 8 related |
750 | | - |
751 | | -'allmessages' => 'სისტემური შეტყობინება', |
752 | | -'allmessagesname' => 'დასახელება', |
753 | | -'allmessagesdefault' => 'სტანდარტული ტექსტი', |
754 | | -'allmessagescurrent' => 'მიმდინარე ტექსტი', |
755 | | -'allmessagestext' => 'ეს არის სახელთა სივრცე მედიავიკიში არსებული სისტემური შეტყობინებების ჩამონათვალი.', |
| 491 | +'allmessages' => 'სისტემური შეტყობინება', |
| 492 | +'allmessagesname' => 'დასახელება', |
| 493 | +'allmessagesdefault' => 'სტანდარტული ტექსტი', |
| 494 | +'allmessagescurrent' => 'მიმდინარე ტექსტი', |
| 495 | +'allmessagestext' => 'ეს არის სახელთა სივრცე მედიავიკიში არსებული სისტემური შეტყობინებების ჩამონათვალი.', |
756 | 496 | 'allmessagesnotsupportedUI' => 'თქვენს ამჟამინდელ ინტერფეისის ენას <b>$1</b> არ აქვს სპეციალური:AllMessages-ის უზრუნველყოფა ამ საიტზე.', |
757 | 497 | 'allmessagesnotsupportedDB' => 'სპეციალური:AllMessages-ის უზრუნველყოფა არ ხდება, ვინაიდან wgUseDatabaseMessages გამორთულია.', |
758 | | -'allmessagesfilter' => 'ფილტრი შეტყობინების სახელის მიხედვით:', |
759 | | -'allmessagesmodified' => 'აჩვენე მხოლოდ შეცვლილი', |
| 498 | +'allmessagesfilter' => 'ფილტრი შეტყობინების სახელის მიხედვით:', |
| 499 | +'allmessagesmodified' => 'აჩვენე მხოლოდ შეცვლილი', |
760 | 500 | |
761 | 501 | # Thumbnails |
762 | | -'thumbnail-more' => 'გაზარდეთ', |
763 | | -#TODO: 'missingimage' => '<b>Missing image</b><br /><i>$1</i>', |
764 | | -'filemissing' => 'ფაილი ვერ მოიძებნა', |
765 | | -'thumbnail_error' => 'ესკიზის შექმნის შეცდომა: $1', |
| 502 | +'thumbnail-more' => 'გაზარდეთ', |
| 503 | +'filemissing' => 'ფაილი ვერ მოიძებნა', |
| 504 | +'thumbnail_error' => 'ესკიზის შექმნის შეცდომა: $1', |
766 | 505 | |
767 | | -# Special:Import |
768 | | - |
769 | | -# import log |
770 | | - |
771 | | -# tooltip help for some actions, most are in Monobook.js |
772 | | - |
773 | | -# stylesheets |
774 | | - |
775 | | -# Metadata |
776 | | - |
777 | 506 | # Attribution |
778 | 507 | 'anonymous' => '{{SITENAME}}-ის ანონიმური მომხმარებლები', |
779 | | -'siteuser' => '{{SITENAME}} მომხმარებელი $1', |
780 | | -#TODO: 'lastmodifiedatby' => 'This page was last modified $2, $1 by $3.', // $1 date, $2 time. $3 user |
781 | | -'and' => 'და', |
782 | | -#TODO: 'othercontribs' => 'Based on work by $1.', |
783 | | -'others' => 'სხვები', |
| 508 | +'siteuser' => '{{SITENAME}} მომხმარებელი $1', |
| 509 | +'and' => 'და', |
| 510 | +'others' => 'სხვები', |
784 | 511 | 'siteusers' => '{{SITENAME}} მომხმარებლები $1', |
785 | | -#TODO: 'creditspage' => 'წვლილი', |
786 | | -#TODO: 'nocredits' => 'There is no credits info available for this page.', |
787 | 512 | |
788 | | -# Spam protection |
789 | | - |
790 | | -# Info page |
791 | | - |
792 | | -# Math options |
793 | | - |
794 | | -# Patrolling |
795 | | - |
796 | | -# Monobook.js: tooltips and access keys for monobook |
797 | | - |
798 | | -# image deletion |
799 | | - |
800 | | -# browsing diffs |
801 | | - |
802 | | -# labels for User: and Title: on Special:Log pages |
803 | | -'specialloguserlabel' => 'მომხმარებელი:', |
804 | | -'speciallogtitlelabel' => 'სათაური:', |
805 | | - |
806 | 513 | 'passwordtooshort' => 'თქვენი პაროლი ძალიან მოკლეა. მასში უნდა შედიოდეს არანაკლებ $1 ასო-ნიშანი.', |
807 | 514 | |
808 | | -# Media Warning |
809 | | -#TODO: 'mediawarning' => '\'\'\'Warning\'\'\': This file may contain malicious code, by executing it your system may be compromised.<hr />', |
810 | | - |
811 | | -'fileinfo' => '$1KB, MIME ტიპი: <code>$2</code>', |
812 | | - |
813 | | -# Metadata |
814 | | - |
815 | | -# Exif tags |
816 | | - |
817 | | -# Make & model, can be wikified in order to link to the camera and model name |
818 | | - |
819 | | -# Exif attributes |
820 | | - |
821 | | -# external editor support |
822 | | - |
823 | 515 | # 'all' in various places, this might be different for inflected languages |
824 | 516 | 'recentchangesall' => 'ყველა', |
825 | | -'imagelistall' => 'ყველა', |
826 | | -'watchlistall1' => 'ყველა', |
827 | | -'watchlistall2' => 'ყველა', |
828 | | -'namespacesall' => 'ყველა', |
| 517 | +'imagelistall' => 'ყველა', |
| 518 | +'watchlistall1' => 'ყველა', |
| 519 | +'watchlistall2' => 'ყველა', |
| 520 | +'namespacesall' => 'ყველა', |
829 | 521 | |
830 | | -# E-mail address confirmation |
831 | | - |
832 | 522 | # Inputbox extension, may be useful in other contexts as well |
833 | | -'tryexact' => 'სცადეთ ზუსტი ძიება', |
| 523 | +'tryexact' => 'სცადეთ ზუსტი ძიება', |
834 | 524 | 'searchfulltext' => 'სრული ტექსტის ძიება', |
835 | | -'createarticle' => 'სტატიის შექმნა', |
| 525 | +'createarticle' => 'სტატიის შექმნა', |
836 | 526 | |
837 | | -# Scary transclusion |
| 527 | +# Delete conflict |
| 528 | +'deletedwhileediting' => "[[მომხმარებელი:$1|$1]] მომხმარებელმა ([[მომხმარებელი განხილვა:$1|განხილვა]]) წაშალა თქვენი რედაქტირების შემდეგ. მიზეზი: |
| 529 | +: ''$2'' |
| 530 | +გთხოვთ დაადასტუროთ რომ ნამდვილად გსურთ ამ გვერდის თავიდან შექმნა.", |
838 | 531 | |
839 | | -# Trackbacks |
840 | | - |
841 | | -# delete conflict |
842 | | - |
843 | | -'deletedwhileediting' => '[[მომხმარებელი:$1|$1]] მომხმარებელმა ([[მომხმარებელი განხილვა:$1|განხილვა]]) წაშალა თქვენი რედაქტირების შემდეგ. მიზეზი: |
844 | | -: \'\'$2\'\' |
845 | | -გთხოვთ დაადასტუროთ რომ ნამდვილად გსურთ ამ გვერდის თავიდან შექმნა.', |
846 | | -#TODO: 'recreate' => 'Recreate', |
847 | | - |
848 | | -#TODO: 'unit-pixel' => 'px', |
849 | | - |
850 | 532 | # HTML dump |
| 533 | +'redirectingto' => 'გადამისამართდება [[$1]]-ზე...', |
851 | 534 | |
852 | 535 | # action=purge |
853 | | -#TODO: 'confirm_purge' => "Clear the cache of this page?\n\n$1", |
854 | | -#TODO: 'confirm_purge_button' => 'OK', |
| 536 | +'confirm_purge' => 'გსურთ ამ გვერდის ქეშის წაშლა? $1', |
855 | 537 | |
856 | | -'youhavenewmessagesmulti' => "თქვენ გაქვთ ახალი შეტყობინება $1-ზე", |
| 538 | +'youhavenewmessagesmulti' => 'თქვენ გაქვთ ახალი შეტყობინება $1-ზე', |
857 | 539 | |
858 | | -#TODO: 'searchcontaining' => "Search for articles containing ''$1''.", |
859 | | -#TODO: 'searchnamed' => "Search for articles named ''$1''.", |
860 | 540 | 'articletitles' => "სტატიები დაწყებული ''$1''-ით", |
861 | | -'hideresults' => 'შედეგების დამალვა', |
| 541 | +'hideresults' => 'შედეგების დამალვა', |
862 | 542 | |
863 | 543 | # DISPLAYTITLE |
864 | 544 | 'displaytitle' => '(ამ გვერდის ბმული როგორც [[$1]])', |
865 | 545 | |
866 | 546 | 'loginlanguagelabel' => 'ენა: $1', |
867 | 547 | |
868 | | -# Multipage image navigation |
869 | | - |
870 | 548 | # Table pager |
871 | | -#TODO: 'ascending_abbrev' => 'asc', |
872 | | -#TODO: 'descending_abbrev' => 'desc', |
873 | | -'table_pager_next' => 'შემდეგი გვერდი', |
874 | | -'table_pager_prev' => 'წინა გვერდი', |
875 | | -'table_pager_first' => 'პირველი გვერდი', |
876 | | -'table_pager_last' => 'ბოლო გვერდი', |
877 | | -#TODO: 'table_pager_limit' => 'Show $1 items per page', |
| 549 | +'table_pager_next' => 'შემდეგი გვერდი', |
| 550 | +'table_pager_prev' => 'წინა გვერდი', |
| 551 | +'table_pager_first' => 'პირველი გვერდი', |
| 552 | +'table_pager_last' => 'ბოლო გვერდი', |
878 | 553 | 'table_pager_limit_submit' => 'აჩვენე', |
879 | | -'table_pager_empty' => 'შედეგები არაა', |
| 554 | +'table_pager_empty' => 'შედეგები არაა', |
880 | 555 | |
881 | 556 | # Auto-summaries |
882 | | -'autosumm-blank' => 'გვერდი დაცარიელდა', |
883 | | -'autosumm-replace' => 'შინაარსი შეიცვალა \'$1\'-ით', |
884 | | -'autoredircomment' => 'გადამისამართება [[$1]]-ზე', # This should be changed to the new naming convention, but existed beforehand. |
885 | | -'autosumm-new' => 'ახალი გვერდი: $1', |
| 557 | +'autosumm-blank' => 'გვერდი დაცარიელდა', |
| 558 | +'autosumm-replace' => "შინაარსი შეიცვალა '$1'-ით", |
| 559 | +'autoredircomment' => 'გადამისამართება [[$1]]-ზე', # This should be changed to the new naming convention, but existed beforehand |
| 560 | +'autosumm-new' => 'ახალი გვერდი: $1', |
886 | 561 | |
887 | 562 | # Size units |
888 | | -'size-bytes' => '$1 ბ', |
| 563 | +'size-bytes' => '$1 ბ', |
889 | 564 | 'size-kilobytes' => '$1 კბ', |
890 | 565 | 'size-megabytes' => '$1 მბ', |
891 | 566 | 'size-gigabytes' => '$1 გბ', |
892 | 567 | |
893 | | - |
894 | 568 | ); |
895 | 569 | |
896 | 570 | ?> |
Index: branches/liquidthreads/languages/messages/MessagesZh_classical.php |
— | — | @@ -29,7 +29,10 @@ |
30 | 30 | * The special key "default" is an alias for either dmy or mdy depending on |
31 | 31 | * $wgAmericanDates |
32 | 32 | */ |
33 | | -$datePreferences = false; |
| 33 | +$datePreferences = array( |
| 34 | + 'default', |
| 35 | + 'ISO 8601', |
| 36 | +); |
34 | 37 | |
35 | 38 | $defaultDateFormat = 'zh'; |
36 | 39 | |
— | — | @@ -43,12 +46,27 @@ |
44 | 47 | */ |
45 | 48 | $dateFormats = array( |
46 | 49 | 'zh time' => 'H時i分', |
47 | | - 'zh date' => 'Y年Fj日', |
48 | | - 'zh both' => 'Y年Fj日H時i分', |
| 50 | + 'zh date' => 'Y年n月j日 (l)', |
| 51 | + 'zh both' => 'Y年n月j日 (D) H時i分', |
49 | 52 | ); |
50 | 53 | |
51 | 54 | $linkTrail = '/^([a-z]+)(.*)$/sD'; |
52 | 55 | |
| 56 | +$digitTransformTable = array( |
| 57 | + '0' => '〇', |
| 58 | + '1' => '一', |
| 59 | + '2' => '二', |
| 60 | + '3' => '三', |
| 61 | + '4' => '四', |
| 62 | + '5' => '五', |
| 63 | + '6' => '六', |
| 64 | + '7' => '七', |
| 65 | + '8' => '八', |
| 66 | + '9' => '九', |
| 67 | + '.' => '點', |
| 68 | + ',' => '', |
| 69 | +); |
| 70 | + |
53 | 71 | #------------------------------------------------------------------- |
54 | 72 | # Default messages |
55 | 73 | #------------------------------------------------------------------- |
— | — | @@ -151,7 +169,8 @@ |
152 | 170 | 'dec' => '十二月', |
153 | 171 | |
154 | 172 | # Bits of text used by many pages |
155 | | -'categories' => '$1類', |
| 173 | +'categories' => '類', |
| 174 | +'pagecategories' => '$1類', |
156 | 175 | 'category_header' => '"$1"文', |
157 | 176 | 'subcategories' => '次類', |
158 | 177 | |
— | — | @@ -214,7 +233,6 @@ |
215 | 234 | 'specialpage' => '奇頁', |
216 | 235 | 'personaltools' => '家私', |
217 | 236 | 'postcomment' => '贊', |
218 | | -'addsection' => '新議', |
219 | 237 | 'articlepage' => '閱內文', |
220 | 238 | 'talk' => '議', |
221 | 239 | 'views' => '覽', |
— | — | @@ -381,10 +399,9 @@ |
382 | 400 | 'yourlanguage' => '語', |
383 | 401 | 'yournick' => '暱名', |
384 | 402 | 'email' => '電郵', |
385 | | -'prefs-help-email-enotif' => '信遣此', |
386 | | -'prefs-help-realname' => '*本名,可略: if you choose to provide it this will be used for giving you attribution for your work.', |
| 403 | +'prefs-help-realname' => '本名可略也。if you choose to provide it this will be used for giving you attribution for your work.', |
387 | 404 | 'loginerror' => '登簿有誤', |
388 | | -'prefs-help-email' => '*電郵,可略:以此通他人,或於共議處匿論', |
| 405 | +'prefs-help-email' => '電郵可略也。以此通他人,或於共議處匿論。', |
389 | 406 | 'nocookiesnew' => '簿已增而未登。登簿{{SITENAME}}須cookies,請釋之後登。', |
390 | 407 | 'nocookieslogin' => '登簿{{SITENAME}}須cookies,請釋之後登。', |
391 | 408 | 'noname' => '簿名缺', |
— | — | @@ -447,8 +464,13 @@ |
448 | 465 | 'missingcommenttext' => '請贊之', |
449 | 466 | 'blockedtitle' => '子見禁', |
450 | 467 | 'blockedtext' => "<big>'''子名、IP見禁。'''</big> |
451 | | -禁者$1也, 因''$2''故,存惑可詢$1,或[[{{ns:project}}:Administrators|有秩]],[[Special:Preferences|簿註]]無驛則信不遣。 |
452 | | -另,子IP為$3,詢時切附之。", |
| 468 | + |
| 469 | +禁者$1也,因''$2''故。 |
| 470 | + |
| 471 | +終止之時為:$6 |
| 472 | + |
| 473 | +存惑可詢$1,或[[{{ns:project}}:Administrators|有秩]],[[Special:Preferences|簿註]]無驛則信不遣。 |
| 474 | +另,子IP為$3,其簿名為#$5。詢時切附之。", |
453 | 475 | 'blockedoriginalsource' => "'''$1'''本源如下:", |
454 | 476 | 'blockededitsource' => "子'''$1纂文'''如下:", |
455 | 477 | 'whitelistedittitle' => '登簿以纂', |
— | — | @@ -557,7 +579,7 @@ |
558 | 580 | 'revisiondelete' => '刪、還審', |
559 | 581 | 'revdelete-nooldid-title' => '無此審。', |
560 | 582 | 'revdelete-nooldid-text' => '審未擇,不可為之。', |
561 | | -'revdelete-selected' => '審[[:$1]]已擇。', |
| 583 | +'revdelete-selected' => '審[[:$1]]已擇$2。', |
562 | 584 | 'revdelete-text' => '刪審雖見誌,其文摒公眾,惟有秩可得之。無規則有秩可復還焉。', |
563 | 585 | 'revdelete-legend' => '審,規之以:', |
564 | 586 | 'revdelete-hide-text' => '藏審文', |
— | — | @@ -784,6 +806,7 @@ |
785 | 807 | 'wantedpages' => '缺頁', |
786 | 808 | 'mostrevisions' => '首審之文', |
787 | 809 | 'allpages' => '全頁', |
| 810 | +'randompage' => '清風翻書', |
788 | 811 | 'shortpages' => '短頁', |
789 | 812 | 'longpages' => '長頁', |
790 | 813 | 'listusers' => '盡列有簿', |
— | — | @@ -794,8 +817,8 @@ |
795 | 818 | 'newpages-username' => '名:', |
796 | 819 | 'ancientpages' => '舊頁', |
797 | 820 | 'intl' => '通他語', |
798 | | -'move' => '搬', |
799 | | -'movethispage' => '搬此頁', |
| 821 | +'move' => '遷', |
| 822 | +'movethispage' => '遷此頁', |
800 | 823 | |
801 | 824 | 'categoriespagetext' => '大典有門:', |
802 | 825 | 'version' => '版', |
— | — | @@ -928,13 +951,13 @@ |
929 | 952 | 'protectsub' => '(正錮"$1")', |
930 | 953 | 'confirmprotecttext' => '篤欲錮之?', |
931 | 954 | 'confirmprotect' => '准錮', |
932 | | -'protectmoveonly' => '惟限搬之', |
| 955 | +'protectmoveonly' => '惟限遷之', |
933 | 956 | 'protectcomment' => '錮之有由:', |
934 | 957 | 'unprotectsub' => '(正赦"$1")', |
935 | 958 | 'confirmunprotecttext' => '篤欲赦之?', |
936 | 959 | 'confirmunprotect' => '准赦', |
937 | 960 | 'unprotectcomment' => '赦之有由:', |
938 | | -'protect-unchain' => '准搬之', |
| 961 | +'protect-unchain' => '准遷之', |
939 | 962 | 'protect-text' => '錮級可見<strong>$1</strong>', |
940 | 963 | 'protect-default' => '(予定)', |
941 | 964 | 'protect-level-autoconfirmed' => '驅無簿', |
— | — | @@ -942,7 +965,7 @@ |
943 | 966 | |
944 | 967 | # Restrictions (nouns) |
945 | 968 | 'restriction-edit' => '纂', |
946 | | -'restriction-move' => '搬', |
| 969 | +'restriction-move' => '遷', |
947 | 970 | |
948 | 971 | # Undelete |
949 | 972 | 'undelete' => '覽已刪', |
— | — | @@ -968,7 +991,7 @@ |
969 | 992 | # Contributions |
970 | 993 | 'contributions' => '功績', |
971 | 994 | 'mycontris' => '吾績', |
972 | | -'contribsub2' => '就$1', |
| 995 | +'contribsub2' => '$1之功績 ($2)', |
973 | 996 | 'nocontribs' => '尺斯無易', |
974 | 997 | 'ucnote' => '近<b>$2</b>有<b>$1</b>新易。', |
975 | 998 | 'uclinks' => ' 近$1易,近$2日', |
— | — | @@ -996,12 +1019,12 @@ |
997 | 1020 | 'ipaddress' => 'IP址', |
998 | 1021 | 'ipadressorusername' => 'IP或簿名', |
999 | 1022 | 'ipbexpiry' => '限期', |
1000 | | -'ipbreason' => '綠', |
| 1023 | +'ipbreason' => '緣', |
1001 | 1024 | 'ipbanononly' => '禁名匿', |
1002 | 1025 | 'ipbcreateaccount' => '禁增簿', |
1003 | 1026 | 'ipbsubmit' => '禁此簿', |
1004 | 1027 | 'ipbother' => '它時', |
1005 | | -'ipboptions' => '2 hours:二時,1 day:一日,3 days:三日,1 week:一週,2 weeks:二週,1 month:一月,3 months:三月,6 months:六月,1 year:一年,infinite:永', |
| 1028 | +'ipboptions' => '二時:2 hours,一日:1 day,三日:3 days,一週:1 week,二週:2 weeks,一月:1 month,三月:3 months,六月:6 months,一年:1 year,永:infinite', |
1006 | 1029 | 'ipbotheroption' => '他', |
1007 | 1030 | 'badipaddress' => 'IP不格', |
1008 | 1031 | 'blockipsuccesssub' => '見禁', |
— | — | @@ -1016,13 +1039,13 @@ |
1017 | 1040 | 'expiringblock' => '過$1', |
1018 | 1041 | 'anononlyblock' => '惟名匿', |
1019 | 1042 | 'createaccountblock' => '禁增簿', |
1020 | | -'ipblocklistempty' => '誌空也。', |
| 1043 | +'ipblocklist-empty' => '誌空也。', |
1021 | 1044 | 'blocklink' => '禁', |
1022 | 1045 | 'unblocklink' => '赦', |
1023 | 1046 | 'contribslink' => '功績', |
1024 | 1047 | 'autoblocker' => '近日"[[User:$1|$1]]"用子IP"\'\'\'$2\'\'\'",故禁', |
1025 | 1048 | 'blocklogpage' => '誌禁', |
1026 | | -'blocklogentry' => '禁"[[$1]]"至$2', |
| 1049 | +'blocklogentry' => '禁"[[$1]]"至$2 $3', |
1027 | 1050 | 'unblocklogentry' => '赦$1', |
1028 | 1051 | 'ipb_expiry_invalid' => '限期不格。', |
1029 | 1052 | 'ipb_already_blocked' => '"$1"早禁矣', |
— | — | @@ -1159,8 +1182,10 @@ |
1160 | 1183 | 'confirmemail_noemail' => '[[Special:Preferences|簿註]]有驛。', |
1161 | 1184 | 'confirmemail_send' => '遣核符', |
1162 | 1185 | 'confirmemail_sent' => '核符遣矣', |
1163 | | -'confirmemail_sendfailed' => '信未遣焉,請核郵驛。', |
| 1186 | +'confirmemail_sendfailed' => '信未遣焉,請核郵驛。 |
1164 | 1187 | |
| 1188 | +郵者覆之:$1', |
| 1189 | + |
1165 | 1190 | # Inputbox extension, may be useful in other contexts as well |
1166 | 1191 | 'tryexact' => '查全合', |
1167 | 1192 | 'searchfulltext' => '尋全文', |
— | — | @@ -1202,7 +1227,8 @@ |
1203 | 1228 | 'imgmultipageprev' => '←前頁', |
1204 | 1229 | 'imgmultipagenext' => '次頁→', |
1205 | 1230 | 'imgmultigo' => '往', |
1206 | | -'imgmultigotopre' => '往', |
| 1231 | +'imgmultigotopre' => '往第', |
| 1232 | +'imgmultigotopost' => '頁', |
1207 | 1233 | |
1208 | 1234 | # Table pager |
1209 | 1235 | 'ascending_abbrev' => '升冪', |
Index: branches/liquidthreads/languages/messages/MessagesHe.php |
— | — | @@ -1504,17 +1504,18 @@ |
1505 | 1505 | 'sp-newimages-showfrom' => 'הצג תמונות חדשות החל מ־$1', |
1506 | 1506 | |
1507 | 1507 | # What links here |
1508 | | -'whatlinkshere' => 'דפים המקושרים לכאן', |
1509 | | -'notargettitle' => 'אין דף מטרה', |
1510 | | -'notargettext' => 'לא ציינתם דף מטרה או משתמש לגביו תבוצע פעולה זו.', |
1511 | | -'linklistsub' => '(רשימת קישורים)', |
1512 | | -'linkshere' => "הדפים שלהלן מקושרים לדף '''[[:$1]]''':", |
1513 | | -'nolinkshere' => "אין דפים המקושרים לדף '''[[:$1]]'''.", |
1514 | | -'nolinkshere-ns' => "אין דפים המקושרים לדף '''[[:$1]]''' במרחב השם שנבחר.", |
1515 | | -'isredirect' => 'דף הפניה', |
1516 | | -'istemplate' => 'הכללה', |
1517 | | -'whatlinkshere-prev' => '{{plural:$1|הקודם|$1 הקודמים}}', |
1518 | | -'whatlinkshere-next' => '{{plural:$1|הבא|$1 הבאים}}', |
| 1508 | +'whatlinkshere' => 'דפים המקושרים לכאן', |
| 1509 | +'notargettitle' => 'אין דף מטרה', |
| 1510 | +'notargettext' => 'לא ציינתם דף מטרה או משתמש לגביו תבוצע פעולה זו.', |
| 1511 | +'linklistsub' => '(רשימת קישורים)', |
| 1512 | +'linkshere' => "הדפים שלהלן מקושרים לדף '''[[:$1]]''':", |
| 1513 | +'nolinkshere' => "אין דפים המקושרים לדף '''[[:$1]]'''.", |
| 1514 | +'nolinkshere-ns' => "אין דפים המקושרים לדף '''[[:$1]]''' במרחב השם שנבחר.", |
| 1515 | +'isredirect' => 'דף הפניה', |
| 1516 | +'istemplate' => 'הכללה', |
| 1517 | +'whatlinkshere-prev' => '{{plural:$1|הקודם|$1 הקודמים}}', |
| 1518 | +'whatlinkshere-next' => '{{plural:$1|הבא|$1 הבאים}}', |
| 1519 | +'whatlinkshere-links' => '→ קישורים', |
1519 | 1520 | |
1520 | 1521 | # Block/unblock |
1521 | 1522 | 'blockip' => 'חסימת משתמש', |
Index: branches/liquidthreads/languages/messages/MessagesZh_cn.php |
— | — | @@ -1401,6 +1401,7 @@ |
1402 | 1402 | 'nolinkshere-ns' => '在所选的名字空间内没有页面链接到[[:$1]]。', |
1403 | 1403 | 'isredirect' => '重定向页', |
1404 | 1404 | 'istemplate' => '包含', |
| 1405 | +'whatlinkshere-links' => '(←链入页面)', |
1405 | 1406 | 'whatlinkshere-prev' => '前$1个', |
1406 | 1407 | 'whatlinkshere-next' => '后$1个', |
1407 | 1408 | |
Index: branches/liquidthreads/languages/messages/MessagesId.php |
— | — | @@ -1529,7 +1529,7 @@ |
1530 | 1530 | 'istemplate' => 'dengan templat', |
1531 | 1531 | 'whatlinkshere-prev' => '$1 sebelumnya', |
1532 | 1532 | 'whatlinkshere-next' => '$1 selanjutnya', |
1533 | | -'whatlinkshere-links' => '(← pranala)', |
| 1533 | +'whatlinkshere-links' => '← pranala', |
1534 | 1534 | |
1535 | 1535 | # Block/unblock |
1536 | 1536 | 'blockip' => 'Blokir pengguna', |
Index: branches/liquidthreads/languages/messages/MessagesMy.php |
— | — | @@ -0,0 +1,205 @@ |
| 2 | +<?php |
| 3 | +/** Burmese (Myanmasa) |
| 4 | + * |
| 5 | + * @addtogroup Language |
| 6 | + */ |
| 7 | + |
| 8 | +$messages = array( |
| 9 | +# Dates |
| 10 | +'sunday' => 'တနင်္ဂနွေ', |
| 11 | +'monday' => 'တနင်္လာ', |
| 12 | +'tuesday' => 'အင်္ဂါ', |
| 13 | +'wednesday' => 'ဗုဒ္ဒဟူး', |
| 14 | +'thursday' => 'ကြာသာပတေး', |
| 15 | +'friday' => 'သောကြာ', |
| 16 | +'saturday' => 'စနေ', |
| 17 | +'january' => 'ဇန်နဝါရီ', |
| 18 | +'february' => 'ဖေဖော်ဝါရီ', |
| 19 | +'march' => 'မတ်', |
| 20 | +'april' => 'ဧပြီ', |
| 21 | +'may_long' => 'မေ', |
| 22 | +'june' => 'ဇွန်', |
| 23 | +'july' => 'ဇူလိုင်', |
| 24 | +'august' => 'ဩဂုတ်', |
| 25 | +'september' => 'စက်တင်ဘာ', |
| 26 | +'october' => 'အောက်တိုဘာ', |
| 27 | +'november' => 'နိုဝင်ဘာ', |
| 28 | +'december' => 'ဒီဇင်ဘာ', |
| 29 | +'january-gen' => 'ဇန်နဝါရီ', |
| 30 | +'february-gen' => 'ဖေဖော်ဝါရီ', |
| 31 | +'march-gen' => 'မတ်', |
| 32 | +'april-gen' => 'ဧပြီ', |
| 33 | +'may-gen' => 'မေ', |
| 34 | +'june-gen' => 'ဇွန်', |
| 35 | +'july-gen' => 'ဇူလိုင်', |
| 36 | +'august-gen' => 'ဩဂုတ်', |
| 37 | +'september-gen' => 'စက်တင်ဘာ', |
| 38 | +'october-gen' => 'အောက်တိုဘာ', |
| 39 | +'november-gen' => 'နိုဝင်ဘာ', |
| 40 | +'december-gen' => 'ဒီဇင်ဘာ', |
| 41 | +'may' => 'မေ', |
| 42 | + |
| 43 | +'cancel' => 'မလုပ်တော့ပါ', |
| 44 | +'qbedit' => 'ပြင်ဆင်ရန်', |
| 45 | +'qbspecialpages' => 'အထူးစာမျက်နှာ', |
| 46 | +'mytalk' => 'ကျွန်တော့ပြောရေးဆိုရာ', |
| 47 | +'navigation' => 'အညွှန်း', |
| 48 | + |
| 49 | +'help' => 'အကူအညီ', |
| 50 | +'search' => 'ရှာဖွေရန်', |
| 51 | +'searchbutton' => 'ရှာဖွေရန်', |
| 52 | +'go' => 'သွားပါ', |
| 53 | +'history_short' => 'မှတ်တမ်း', |
| 54 | +'printableversion' => 'ပရင်တာထုတ်ရန်', |
| 55 | +'permalink' => 'ပုံသေလိပ်စာ', |
| 56 | +'edit' => 'ပြင်ဆင်ရန်', |
| 57 | +'delete' => 'ဖျက်ပါ', |
| 58 | +'protect' => 'ထိမ်းသိမ်းပါ', |
| 59 | +'talk' => 'ပြောရေးဆိုရာ', |
| 60 | +'toolbox' => 'တန်ဆာပလာ', |
| 61 | +'otherlanguages' => 'အခြားဘာသာဖြင့်', |
| 62 | +'jumptonavigation' => 'အညွှန်း', |
| 63 | +'jumptosearch' => 'ရှာဖွေရန်', |
| 64 | + |
| 65 | +# All link text and link target definitions of links into project namespace that get used by other message strings, with the exception of user group pages (see grouppage) and the disambiguation template definition (see disambiguations). |
| 66 | +'currentevents' => 'လက်ရှိလုပ်ငန်းများ', |
| 67 | +'currentevents-url' => 'လက်ရှိလုပ်ငန်းများ', |
| 68 | +'disclaimers' => 'သတိပေးချက်များ', |
| 69 | +'edithelp' => 'ပြင်ဆင်ခြင်းအကူအညီ', |
| 70 | +'mainpage' => 'ဗဟိုစာမျက်နှာ', |
| 71 | +'portal' => 'ပြောရေးဆိုရာ', |
| 72 | +'sitesupport' => 'လှုဒါန်းမှု', |
| 73 | + |
| 74 | +'newmessageslink' => 'သတင်းအသစ်', |
| 75 | +'editsection' => 'ပြင်ဆင်ရန်', |
| 76 | +'editold' => 'ပြင်ဆင်ရန်', |
| 77 | + |
| 78 | +# Short words for each namespace, by default used in the 'article' tab in monobook |
| 79 | +'nstab-main' => 'စာမျက်နှာ', |
| 80 | +'nstab-user' => 'မှတ်ပုံတင်အသုံးပြုသူ၏စာမျက်နှာ', |
| 81 | + |
| 82 | +# General errors |
| 83 | +'viewsource' => 'ဆို့ကိုပြပါ', |
| 84 | + |
| 85 | +# Login and logout pages |
| 86 | +'welcomecreation' => 'မင်္ဂလာပါ $1။ သင့်အားမှတ်ပုံတင်ပြီးပါပြီ။ ဝီကီအတွက်သင့်စိတ်ကြိုက်များကိုရွေးချယ်နိုင်ပါသည်။', |
| 87 | +'yourname' => 'မှတ်ပုံတင်အမည်:', |
| 88 | +'yourpassword' => 'လှို့ဝှက်စကားလုံး:', |
| 89 | +'yourpasswordagain' => 'ပြန်ရိုက်ပါ:', |
| 90 | +'remembermypassword' => 'ဤကွန်ပျူတာတွင်ကျွန်တော့ကိုမှတ်ထားပါ', |
| 91 | +'login' => 'မှတ်ပုံတင်ဖြင့်ဝင်ပါ', |
| 92 | +'logout' => 'ထွက်ပါ', |
| 93 | +'userlogout' => 'ထွက်ပါ', |
| 94 | +'notloggedin' => 'မှတ်ပုံတင်ဖြင့်မဝင်ရသေးပါ', |
| 95 | +'createaccount' => 'မှတ်ပုံတင်ပြုလုပ်ပါ', |
| 96 | +'gotaccountlink' => 'မှတ်ပုံတင်ဖြင့်ဝင်ပါ', |
| 97 | +'youremail' => 'အီမေး:', |
| 98 | +'username' => 'မှတ်ပုံတင်အမည်:', |
| 99 | +'email' => 'အီမေး', |
| 100 | + |
| 101 | +# Edit pages |
| 102 | +'summary' => 'အကျဉ်းချုပ်', |
| 103 | +'minoredit' => 'သာမန်ပြင်ဆင်မှုဖြစ်ပါသည်', |
| 104 | +'watchthis' => 'ဤစာမျက်နှာအားစောင့်ကြည့်ပါ', |
| 105 | +'savearticle' => 'သိမ်းပါ', |
| 106 | +'showpreview' => 'နမူနာပြပါ', |
| 107 | +'showdiff' => 'ပြင်ဆင်ထားသည်များကိုပြပါ', |
| 108 | +'whitelistedittitle' => 'ပြင်ဆင်ခြင်းသည်မှတ်ပုံတင်ရန်လိုသည်', |
| 109 | +'loginreqlink' => 'မှတ်ပုံတင်ဖြင့်ဝင်ပါ', |
| 110 | + |
| 111 | +# Search results |
| 112 | +'powersearch' => 'ရှာဖွေရန်', |
| 113 | + |
| 114 | +# Preferences page |
| 115 | +'mypreferences' => 'ကျွန်တော့ရွေးချယ်စရာများ', |
| 116 | +'prefsnologin' => 'မှတ်ပုံတင်ဖြင့်မဝင်ရသေးပါ', |
| 117 | +'searchresultshead' => 'ရှာဖွေရန်', |
| 118 | + |
| 119 | +# Recent changes |
| 120 | +'recentchanges' => 'လတ်တလောအပြောင်းအလဲများ', |
| 121 | + |
| 122 | +# Recent changes linked |
| 123 | +'recentchangeslinked' => 'ဆက်ဆပ်သောအပြောင်းအလဲများ', |
| 124 | + |
| 125 | +# Upload |
| 126 | +'upload' => 'ဖိုင်တင်ရန်', |
| 127 | +'uploadbtn' => 'ဖိုင်တင်ရန်', |
| 128 | +'uploadnologin' => 'မှတ်ပုံတင်ဖြင့်မဝင်ရသေးပါ', |
| 129 | +'filedesc' => 'အကျဉ်းချုပ်', |
| 130 | +'fileuploadsummary' => 'အကျဉ်းချုပ်:', |
| 131 | +'watchthisupload' => 'ဤစာမျက်နှာအားစောင့်ကြည့်ပါ', |
| 132 | + |
| 133 | +# Image list |
| 134 | +'ilsubmit' => 'ရှာဖွေရန်', |
| 135 | + |
| 136 | +'brokenredirects-edit' => '(ပြင်ဆင်ရန်)', |
| 137 | +'brokenredirects-delete' => '(ဖျက်ပါ)', |
| 138 | + |
| 139 | +# Miscellaneous special pages |
| 140 | +'randompage' => 'ကျပန်းစာမျက်နှာ', |
| 141 | +'specialpages' => 'အထူးစာမျက်နှာ', |
| 142 | +'newpages-username' => 'မှတ်ပုံတင်အမည်:', |
| 143 | +'move' => 'ရွေ့ပြောင်းပါ', |
| 144 | + |
| 145 | +# Book sources |
| 146 | +'booksources-go' => 'သွားပါ', |
| 147 | + |
| 148 | +# Special:Log |
| 149 | +'log-search-submit' => 'သွားပါ', |
| 150 | + |
| 151 | +# Special:Allpages |
| 152 | +'allpagessubmit' => 'သွားပါ', |
| 153 | + |
| 154 | +# Watchlist |
| 155 | +'watchlist' => 'စောင့်ကြည့်စာရင်း', |
| 156 | +'mywatchlist' => 'စောင့်ကြည့်စာရင်း', |
| 157 | +'watch' => 'စောင့်ကြည့်ပါ', |
| 158 | +'watchthispage' => 'ဤစာမျက်နှာအားစောင့်ကြည့်ပါ', |
| 159 | + |
| 160 | +# Restrictions (nouns) |
| 161 | +'restriction-edit' => 'ပြင်ဆင်ရန်', |
| 162 | +'restriction-move' => 'ရွေ့ပြောင်းပါ', |
| 163 | + |
| 164 | +# Undelete |
| 165 | +'undelete-search-submit' => 'ရှာဖွေရန်', |
| 166 | + |
| 167 | +# Contributions |
| 168 | +'contributions' => 'မှတ်ပုံတင်အသုံးပြုသူ:ပံပိုးမှုများ', |
| 169 | +'mycontris' => 'ကျွန်တော်ပေးသောပံပိုးမှုများ', |
| 170 | + |
| 171 | +'sp-contributions-submit' => 'ရှာဖွေရန်', |
| 172 | + |
| 173 | +# What links here |
| 174 | +'whatlinkshere' => 'မည်သည့်စာမျက်နှာများမှညွန်းထားသည်', |
| 175 | + |
| 176 | +# Block/unblock |
| 177 | +'ipbreason' => 'အကြောင်းပြချက်:', |
| 178 | +'ipblocklist-submit' => 'ရှာဖွေရန်', |
| 179 | + |
| 180 | +# Move page |
| 181 | +'movepage' => 'စာမျက်နှာအားရွေ့ပြောင်းပါ', |
| 182 | +'movearticle' => 'စာမျက်နှာအားရွေ့ပြောင်းပါ', |
| 183 | +'movenologin' => 'မှတ်ပုံတင်ဖြင့်မဝင်ရသေးပါ', |
| 184 | +'movepagebtn' => 'စာမျက်နှာအားရွေ့ပြောင်းပါ', |
| 185 | +'movedto' => 'ရွေ့ပြောင်းရန်နေရာ', |
| 186 | +'1movedto2' => '[[$1]] မှ [[$2]] သို့', |
| 187 | +'movereason' => 'အကြောင်းပြချက်', |
| 188 | + |
| 189 | +# Namespace 8 related |
| 190 | +'allmessages' => 'စနစ်၏သတင်းများ', |
| 191 | + |
| 192 | +# Tooltip help for the actions |
| 193 | +'tooltip-pt-logout' => 'ထွက်ပါ', |
| 194 | +'tooltip-ca-move' => 'ဤစာမျက်နှာအားရွေ့ပြောင်းပါ', |
| 195 | + |
| 196 | +'youhavenewmessagesmulti' => 'သင့်အတွက်သီတင်းအသစ် $1 တွင်ရှိသည်', |
| 197 | + |
| 198 | +# Multipage image navigation |
| 199 | +'imgmultigo' => 'သွားပါ!', |
| 200 | + |
| 201 | +# Table pager |
| 202 | +'table_pager_limit_submit' => 'သွားပါ', |
| 203 | + |
| 204 | +); |
| 205 | + |
| 206 | +?> |
Property changes on: branches/liquidthreads/languages/messages/MessagesMy.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 207 | + native |
Index: branches/liquidthreads/languages/messages/MessagesZh_tw.php |
— | — | @@ -1378,6 +1378,7 @@ |
1379 | 1379 | 'nolinkshere-ns' => '在所選的名字空間內沒有頁面鏈接到[[:$1]]。', |
1380 | 1380 | 'isredirect' => '重定向頁', |
1381 | 1381 | 'istemplate' => '包含', |
| 1382 | +'whatlinkshere-links' => '(← 鏈入頁面)', |
1382 | 1383 | 'whatlinkshere-prev' => '前$1個', |
1383 | 1384 | 'whatlinkshere-next' => '後$1個', |
1384 | 1385 | |
Index: branches/liquidthreads/languages/messages/MessagesKk_tr.php |
— | — | @@ -167,7 +167,7 @@ |
168 | 168 | 'localmonth' => array( 1, 'JERGİLİKTİAÝ', 'LOCALMONTH' ), |
169 | 169 | 'localmonthname' => array( 1, 'JERGİLİKTİAÝATAWI', 'LOCALMONTHNAME' ), |
170 | 170 | 'localmonthnamegen' => array( 1, 'JERGİLİKTİAÝİLİKATAWI', 'LOCALMONTHNAMEGEN' ), |
171 | | - 'localmonthabbrev' => array( 1, 'JERGİLİKTİAÝJÏIR', 'JERGİLİKTİAÝQISQA', 'LOCALMONTHABBREV' ), |
| 171 | + 'localmonthabbrev' => array( 1, 'JERGİLİKTİAÝJÏIR', 'JERGİLİKTİAÝQISQAŞA', 'JERGİLİKTİAÝQISQA', 'LOCALMONTHABBREV' ), |
172 | 172 | 'localday' => array( 1, 'JERGİLİKTİKÜN', 'LOCALDAY' ), |
173 | 173 | 'localday2' => array( 1, 'JERGİLİKTİKÜN2', 'LOCALDAY2' ), |
174 | 174 | 'localdayname' => array( 1, 'JERGİLİKTİKÜNATAWI', 'LOCALDAYNAME' ), |
— | — | @@ -189,8 +189,8 @@ |
190 | 190 | 'subjectspacee' => array( 1, 'TAQIRIPBETİ2', 'MAQALABETİ2', 'SUBJECTSPACEE', 'ARTICLESPACEE' ), |
191 | 191 | 'fullpagename' => array( 1, 'TOLIQBETATAWI', 'FULLPAGENAME' ), |
192 | 192 | 'fullpagenamee' => array( 1, 'TOLIQBETATAWI2', 'FULLPAGENAMEE' ), |
193 | | - 'subpagename' => array( 1, 'ASTIÑĞIBETATAWI', 'SUBPAGENAME' ), |
194 | | - 'subpagenamee' => array( 1, 'ASTIÑĞIBETATAWI2', 'SUBPAGENAMEE' ), |
| 193 | + 'subpagename' => array( 1, 'BETŞEATAWI', 'ASTIÑĞIBETATAWI', 'SUBPAGENAME' ), |
| 194 | + 'subpagenamee' => array( 1, 'BETŞEATAWI2', 'ASTIÑĞIBETATAWI2', 'SUBPAGENAMEE' ), |
195 | 195 | 'basepagename' => array( 1, 'NEGİZGİBETATAWI', 'BASEPAGENAME' ), |
196 | 196 | 'basepagenamee' => array( 1, 'NEGİZGİBETATAWI2', 'BASEPAGENAMEE' ), |
197 | 197 | 'talkpagename' => array( 1, 'TALQILAWBETATAWI', 'TALKPAGENAME' ), |
— | — | @@ -208,6 +208,7 @@ |
209 | 209 | 'img_width' => array( 1, '$1 px', '$1px' ), |
210 | 210 | 'img_center' => array( 1, 'ortağa', 'orta', 'center', 'centre' ), |
211 | 211 | 'img_framed' => array( 1, 'sürmeli', 'framed', 'enframed', 'frame' ), |
| 212 | + 'img_frameless' => array( 1, 'sürmesiz', 'frameless' ), |
212 | 213 | 'img_page' => array( 1, 'bet=$1', 'bet $1', 'page=$1', 'page $1' ), |
213 | 214 | 'img_upright' => array( 1, 'tikti', 'tiktik=$1', 'tiktik $1' ), |
214 | 215 | 'img_border' => array( 1, 'şekti' ), |
— | — | @@ -221,18 +222,18 @@ |
222 | 223 | 'img_text-bottom' => array( 1, 'mätin-astında', 'text-bottom' ), |
223 | 224 | 'int' => array( 0, 'İŞKİ:', 'INT:' ), |
224 | 225 | 'sitename' => array( 1, 'TORAPATAWI', 'SITENAME' ), |
225 | | - 'ns' => array( 0, 'EA:', 'NS:' ), |
| 226 | + 'ns' => array( 0, 'EA:', 'ESİMAYA:', 'NS:' ), |
226 | 227 | 'localurl' => array( 0, 'JERGİLİKTİJAÝ:', 'LOCALURL:' ), |
227 | 228 | 'localurle' => array( 0, 'JERGİLİKTİJAÝ2:', 'LOCALURLE:' ), |
228 | 229 | 'server' => array( 0, 'SERVER', 'SERVER' ), |
229 | 230 | 'servername' => array( 0, 'SERVERATAWI', 'SERVERNAME' ), |
230 | 231 | 'scriptpath' => array( 0, 'ÄMİRJOLI', 'SCRIPTPATH' ), |
231 | | - 'grammar' => array( 0, 'SEPTİK:', 'GRAMMAR:' ), |
| 232 | + 'grammar' => array( 0, 'SEPTİGİ:', 'SEPTİK:', 'GRAMMAR:' ), |
232 | 233 | 'notitleconvert' => array( 0, '__ATAWALMASTIRĞIZBAW__', '__AABAW__', '__NOTITLECONVERT__', '__NOTC__' ), |
233 | 234 | 'nocontentconvert' => array( 0, '__MAĞLUMATALMASTIRĞIZBAW__', '__MABAW__', '__NOCONTENTCONVERT__', '__NOCC__' ), |
234 | | - 'currentweek' => array( 1, 'AĞIMDAĞIAPTA', 'CURRENTWEEK' ), |
| 235 | + 'currentweek' => array( 1, 'AĞIMDAĞIAPTASI', 'AĞIMDAĞIAPTA', 'CURRENTWEEK' ), |
235 | 236 | 'currentdow' => array( 1, 'AĞIMDAĞIAPTAKÜNİ', 'CURRENTDOW' ), |
236 | | - 'localweek' => array( 1, 'JERGİLİKTİAPTA', 'LOCALWEEK' ), |
| 237 | + 'localweek' => array( 1, 'JERGİLİKTİAPTASI', 'JERGİLİKTİAPTA', 'LOCALWEEK' ), |
237 | 238 | 'localdow' => array( 1, 'JERGİLİKTİAPTAKÜNİ', 'LOCALDOW' ), |
238 | 239 | 'revisionid' => array( 1, 'NUSQANÖMİRİ', 'REVISIONID' ), |
239 | 240 | 'revisionday' => array( 1, 'NUSQAKÜNİ' , 'REVISIONDAY' ), |
— | — | @@ -240,13 +241,13 @@ |
241 | 242 | 'revisionmonth' => array( 1, 'NUSQAAÝI', 'REVISIONMONTH' ), |
242 | 243 | 'revisionyear' => array( 1, 'NUSQAJILI', 'REVISIONYEAR' ), |
243 | 244 | 'revisiontimestamp' => array( 1, 'NUSQAWAQITTÜÝİNDEMESİ', 'REVISIONTIMESTAMP' ), |
244 | | - 'plural' => array( 0, 'KÖPŞE:', 'PLURAL:' ), |
245 | | - 'fullurl' => array( 0, 'TOLIQJAÝ:', 'FULLURL:' ), |
246 | | - 'fullurle' => array( 0, 'TOLIQJAÝ2:', 'FULLURLE:' ), |
247 | | - 'lcfirst' => array( 0, 'KÄ1:', 'LCFIRST:' ), |
248 | | - 'ucfirst' => array( 0, 'BÄ1:', 'UCFIRST:' ), |
249 | | - 'lc' => array( 0, 'KÄ:', 'LC:' ), |
250 | | - 'uc' => array( 0, 'BÄ:', 'UC:' ), |
| 245 | + 'plural' => array( 0, 'KÖPŞETÜRİ:','KÖPŞE:', 'PLURAL:' ), |
| 246 | + 'fullurl' => array( 0, 'TOLIQJAÝI:', 'TOLIQJAÝ:', 'FULLURL:' ), |
| 247 | + 'fullurle' => array( 0, 'TOLIQJAÝI2:', 'TOLIQJAÝ2:', 'FULLURLE:' ), |
| 248 | + 'lcfirst' => array( 0, 'KÄ1:', 'KİŞİÄRİPPEN1:', 'LCFIRST:' ), |
| 249 | + 'ucfirst' => array( 0, 'BÄ1:', 'BASÄRİPPEN1:', 'UCFIRST:' ), |
| 250 | + 'lc' => array( 0, 'KÄ:', 'KİŞİÄRİPPEN:', 'LC:' ), |
| 251 | + 'uc' => array( 0, 'BÄ:', 'BASÄRİPPEN:', 'UC:' ), |
251 | 252 | 'raw' => array( 0, 'QAM:', 'RAW:' ), |
252 | 253 | 'displaytitle' => array( 1, 'KÖRSETİLETİNATAW', 'DISPLAYTITLE' ), |
253 | 254 | 'rawsuffix' => array( 1, 'Q', 'R' ), |
— | — | @@ -262,8 +263,8 @@ |
263 | 264 | 'pagesinnamespace' => array( 1, 'ESİMAYABETSANI:', 'EABETSANI:', 'AYABETSANI:', 'PAGESINNAMESPACE:', 'PAGESINNS:' ), |
264 | 265 | 'numberofadmins' => array( 1, 'ÄKİMŞİSANI', 'NUMBEROFADMINS' ), |
265 | 266 | 'formatnum' => array( 0, 'SANPİŞİMİ', 'FORMATNUM' ), |
266 | | - 'padleft' => array( 0, 'SOLIĞIS', 'PADLEFT' ), |
267 | | - 'padright' => array( 0, 'OÑIĞIS', 'PADRIGHT' ), |
| 267 | + 'padleft' => array( 0, 'SOLĞAIĞIS', 'SOLIĞIS', 'PADLEFT' ), |
| 268 | + 'padright' => array( 0, 'OÑĞAIĞIS', 'OÑIĞIS', 'PADRIGHT' ), |
268 | 269 | 'special' => array( 0, 'arnaýı', 'special', ), |
269 | 270 | 'defaultsort' => array( 1, 'ÄDEPKİSURIPTAW:', 'ÄDEPKİSURIP:', 'DEFAULTSORT:' ), |
270 | 271 | ); |
— | — | @@ -348,7 +349,7 @@ |
349 | 350 | $messages = array( |
350 | 351 | # User preference toggles |
351 | 352 | 'tog-underline' => 'Siltemeni astınan sız:', |
352 | | -'tog-highlightbroken' => 'Joqtalğan siltemelerdi <a href="" class="new">bılaý</a> pişimde (basqaşa: bılaý <a href="" class="internal">?</a> sïyaqtı).', |
| 353 | +'tog-highlightbroken' => 'Jaramsız siltemelerdi <a href="" class="new">bılaý</a> pişimde (balaması: bılaý <a href="" class="internal">?</a> sïyaqtı).', |
353 | 354 | 'tog-justify' => 'Ejelerdi eni boýınşa twralaw', |
354 | 355 | 'tog-hideminor' => 'Jwıqtağı özgeristerde şağın tüzetwdi jasır', |
355 | 356 | 'tog-extendwatchlist' => 'Baqılaw tizimdi ulğaýt (barlıq jaramdı özgeristerdi körset)', |
— | — | @@ -449,7 +450,7 @@ |
450 | 451 | 'categories' => 'Barlıq sanat tizimi', |
451 | 452 | 'pagecategories' => '{{PLURAL:$1|Sanat|Sanattar}}', |
452 | 453 | 'category_header' => '«$1» sanatındağı better', |
453 | | -'subcategories' => 'Tömengi sanattar', |
| 454 | +'subcategories' => 'Sanatşalar', |
454 | 455 | 'category-media-header' => '«$1» sanatındağı taspalar', |
455 | 456 | |
456 | 457 | 'linkprefix' => '/^(.*?)([a-zäçéğıïñöşüýа-яёәіңғүұқөһA-ZÄÇÉĞİÏÑÖŞÜÝА-ЯЁӘІҢҒҮҰҚӨҺʺʹ«„]+)$/sDu', |
— | — | @@ -888,7 +889,7 @@ |
889 | 890 | 'nonunicodebrowser' => '<strong>AÑĞARTPA: Şolğışıñız Unicode belgilewine üýlesimdi emes, sondıqtan latın emes äripteri bar betterdi öñdew zil bolw mümkin. Jumıs istewge ıqtïmaldıq berw üşin, tömengi öñdew awmağında ASCII emes äripter onaltılıq sanımen körsetiledi</strong>.', |
890 | 891 | 'editingold' => '<strong>AÑĞARTPA: Osı bettiñ erterek nusqasın |
891 | 892 | öñdep jatırsız. |
892 | | -Bunı saqtasañız, osı nwsqadan soñğı barlıq tüzetwler joýıladı.</strong>', |
| 893 | +Bunı saqtasañız, osı nwsqadan soñğı barlıq özgerister joýıladı.</strong>', |
893 | 894 | 'yourdiff' => 'Aýırmalar', |
894 | 895 | 'copyrightwarning' => '{{SITENAME}} jobasına qosılğan bükil üles $2 (köbirek aqparat üşin: $1) qujatına saý jiberilgen bolıp sanaladı. Eger jazwıñızdıñ erkin köşirilip tüzetilwin qalamasañız, mında usınbawıñız jön.<br /> |
895 | 896 | Tağı, qosqan ülesiñiz - öziñizdiñ jazğanığız, ne aşıq aqparat közderinen alınğan mağlumat bolğanın wäde etesiz.<br /> |
— | — | @@ -1069,7 +1070,7 @@ |
1070 | 1071 | 'qbsettings-fixedright' => 'Oñğa bekitilgen', |
1071 | 1072 | 'qbsettings-floatingleft' => 'Solğa qalqığan', |
1072 | 1073 | 'qbsettings-floatingright' => 'Oñğa qalqığan', |
1073 | | -'changepassword' => 'Qupïya söz özgertw', |
| 1074 | +'changepassword' => 'Qupïya sözdi awıstırw', |
1074 | 1075 | 'skin' => 'Bezendirw', |
1075 | 1076 | 'math' => 'Matematïka', |
1076 | 1077 | 'dateformat' => 'Kün-aý pişimi', |
— | — | @@ -1151,7 +1152,7 @@ |
1152 | 1153 | 'rightsnone' => '(eşqandaý)', |
1153 | 1154 | |
1154 | 1155 | # Recent changes |
1155 | | -'nchanges' => '{{PLURAL:$1|bir tüzetw|$1 tüzetw}}', |
| 1156 | +'nchanges' => '{{PLURAL:$1|bir özgeris|$1 özgeris}}', |
1156 | 1157 | 'recentchanges' => 'Jwıqtağı özgerister', |
1157 | 1158 | 'recentchangestext' => 'Bul bette osı wïkïdegi bolğan jwıqtağı özgerister baýqaladı.', |
1158 | 1159 | 'recentchanges-feed-description' => 'Bul arnamenen wïkïdegi eñ soñğı özgerister qadağalanadı.', |
— | — | @@ -1178,9 +1179,9 @@ |
1179 | 1180 | 'rc_categories_any' => 'Qaýsıbir', |
1180 | 1181 | |
1181 | 1182 | # Recent changes linked |
1182 | | -'recentchangeslinked' => 'Qatıstı tüzetwler', |
| 1183 | +'recentchangeslinked' => 'Qatıstı özgerister', |
1183 | 1184 | 'recentchangeslinked-noresult' => 'Siltegen betterde aýtılmış merzimde eşqandaý özgeris bolmağan.', |
1184 | | -'recentchangeslinked-summary' => "Bul arnaýı bette siltegen betterdegi jwıqtağı özgerister tizimi beriledi. Baqılaw tizimiñizdegi better '''jwan''' ärpimen belgilenedi.", |
| 1185 | +'recentchangeslinked-summary' => "Bul arnaýı bette siltegen betterdegi jwıqtağı özgerister tizimi beriledi. Baqılaw tizimiñizdegi better '''jwan''' ärbimen belgilenedi.", |
1185 | 1186 | |
1186 | 1187 | # Upload |
1187 | 1188 | 'upload' => 'Faýl qotarw', |
— | — | @@ -1218,8 +1219,8 @@ |
1219 | 1220 | 'filetype-missing' => 'Bul faýldıñ («.jpg» sïyaqtı) keñeýtimi joq.', |
1220 | 1221 | 'large-file' => 'Faýldı $1 mölşerden aspawına tırısıñız; bul faýl mölşeri — $2.', |
1221 | 1222 | 'largefileserver' => 'Osı faýldıñ mölşeri serverdiñ qalawınan asıp ketken.', |
1222 | | -'emptyfile' => 'Qotarılğan faýlıñız bos sïyaqtı. Bul faýl atawı jansaq engizilgeninen bolwı mümkin. Qotarğıñız kelgen faýl şınında da osı faýl bolğanın tekserip alıñız.', |
1223 | | -'fileexists' => 'Osındaý atawlı faýl bar tüge. Qaýta jazwdıñ aldınan $1 tekserip şığıñız.', |
| 1223 | +'emptyfile' => 'Qotarılğan faýlıñız bos sïyaqtı. Bul faýl atawında qate bolwı mümkin. Osı faýldı şınaýı qotarğıñız keletin tekserip şığıñız.', |
| 1224 | +'fileexists' => 'Osındaý atawlı faýl bar tüge, eger bunı özgertwge senimiñiz joq bolsa <strong><tt>$1</tt></strong> degendi tekserip şığıñız.', |
1224 | 1225 | 'fileexists-extension' => 'Uqsastı faýl atawı bar tüge:<br /> |
1225 | 1226 | Qotarılatın faýl atawı: <strong><tt>$1</tt></strong><br /> |
1226 | 1227 | Bar bolğan faýl atawı: <strong><tt>$2</tt></strong><br /> |
— | — | @@ -1306,7 +1307,7 @@ |
1307 | 1308 | |
1308 | 1309 | # MIME search |
1309 | 1310 | 'mimesearch' => 'Faýldı MIME türimen izdew', |
1310 | | -'mimesearch-summary' => 'Bul bet faýldardı MIME türimen süzgilew mümkindigin beredi. Kirisi: «mağlumat türi»/«taraw türi», mısalı <tt>image/jpeg</tt>.', |
| 1311 | +'mimesearch-summary' => 'Bul bet faýldardı MIME türimen süzgilew mümkindigin beredi. Kirisi: «mağlumat türi»/«tür tarawı», mısalı <tt>image/jpeg</tt>.', |
1311 | 1312 | 'mimetype' => 'MIME türi:', |
1312 | 1313 | 'download' => 'jüktew', |
1313 | 1314 | |
— | — | @@ -1520,7 +1521,7 @@ |
1521 | 1522 | * [[{{ns:special}}:Watchlist/edit|Bükil tizimdi qaraw jäne özgertw]]. |
1522 | 1523 | * [[{{ns:special}}:Watchlist/clear|Tizimdegi barlıq dana alastatw]].", |
1523 | 1524 | 'wlheader-enotif' => '* Eskertw xat jiberwi endirilgen.', |
1524 | | -'wlheader-showupdated' => "* Soñğı kirgenimnen beri tüzetilgen betterdi '''jwan''' mätinmen körset", |
| 1525 | +'wlheader-showupdated' => "* Soñğı kirgenimnen beri özgertilgen betterdi '''jwan''' ärbimen körset", |
1525 | 1526 | 'watchmethod-recent' => 'baqılawlı betterdiñ jwıqtağı özgeristerin tekserw', |
1526 | 1527 | 'watchmethod-list' => 'jwıqtağı özgeristerde baqılawlı betterdi tekserw', |
1527 | 1528 | 'removechecked' => 'Belgilengendi baqılaw tiziminen alastatw', |
— | — | @@ -1621,7 +1622,7 @@ |
1622 | 1623 | «Artqa» tüýmesin basıñız, jäne betti keri jükteñiz, sosın qaýtalap köriñiz.', |
1623 | 1624 | 'protectlogpage' => 'Qorğaw_jwrnalı', |
1624 | 1625 | 'protectlogtext' => 'Tömende betterdiñ qorğaw/qorğamaw tizimi berilgen. Ağımdağı qorğaw ärektter bar better üşin [[{{ns:special}}:Protectedpages|qorğalğan bet tizimin]] qarañız.', |
1625 | | -'protectedarticle' => '«$1» qorğaldı', |
| 1626 | +'protectedarticle' => '«[[$1]]» qorğaldı', |
1626 | 1627 | 'unprotectedarticle' => '«[[$1]]» qorğalmadı', |
1627 | 1628 | 'protectsub' => '(«$1» qorğawda)', |
1628 | 1629 | 'confirmprotecttext' => 'Osı betti rasında da qorğaw qajet pe?', |
— | — | @@ -1651,7 +1652,7 @@ |
1652 | 1653 | 'protect-expiring' => 'bitwi: $1 (UTC)', |
1653 | 1654 | 'protect-cascade' => 'Bawlı qorğaw — bul betke kiristirilgen ärqaýsı betterdi qorğaw.', |
1654 | 1655 | 'restriction-type' => 'Ruqsatı:', |
1655 | | -'restriction-level' => 'Ruqsat deñgeýi:', |
| 1656 | +'restriction-level' => 'Ruqsat şektew deñgeýi:', |
1656 | 1657 | 'minimum-size' => 'Eñ az mölşeri', |
1657 | 1658 | 'maximum-size' => 'Eñ köp mölşeri', |
1658 | 1659 | 'pagesize' => '(baýt)', |
— | — | @@ -1695,7 +1696,7 @@ |
1696 | 1697 | 'undeletedarticle' => '«[[$1]]» qaýtardı', |
1697 | 1698 | 'undeletedrevisions' => '{{PLURAL:$1|Nusqanı|$1 nusqanı}} qaýtardı', |
1698 | 1699 | 'undeletedrevisions-files' => '{{PLURAL:$1|Nusqanı|$1 nusqanı}} jäne {{PLURAL:$2|faýldı|$2 faýldı}} qaýtardı', |
1699 | | -'undeletedfiles' => '{{PLURAL:$1|1 faýl|$1 faýl}} qaýtardı', |
| 1700 | +'undeletedfiles' => '{{PLURAL:$1|1 faýldı|$1 faýldı}} qaýtardı', |
1700 | 1701 | 'cannotundelete' => 'Qaýtarw sätsiz bitti; tağı birew sizden burın sol betti qaýtarğan bolar.', |
1701 | 1702 | 'undeletedpage' => "<big>'''$1 qaýtarıldı'''</big> |
1702 | 1703 | |
— | — | @@ -1746,6 +1747,7 @@ |
1747 | 1748 | 'istemplate' => 'kiriktirw', |
1748 | 1749 | 'whatlinkshere-prev' => '{{PLURAL:$1|aldıñğı|aldıñğı $1}}', |
1749 | 1750 | 'whatlinkshere-next' => '{{PLURAL:$1|kelesi|kelesi $1}}', |
| 1751 | +'whatlinkshere-links' => '← siltemeler', |
1750 | 1752 | |
1751 | 1753 | # Block/unblock |
1752 | 1754 | 'blockip' => 'Paýdalanwşını buğattaw', |
— | — | @@ -1866,7 +1868,7 @@ |
1867 | 1869 | barlıq tarïxın jaña atawğa jıljıtadı. |
1868 | 1870 | Burınğı bet atawı jaña atawğa aýdatatın bet boladı. |
1869 | 1871 | Eski atawına silteýtin siltemeler özgertilmeýdi; jıljıtwdan soñ |
1870 | | -şınjırlı aýdatwlar bar-joğın tekseriñiz. |
| 1872 | +şınjırlı ne jaramsız aýdatwlar bar-joğın tekserip şığıñız. |
1871 | 1873 | Siltemeler burınğı joldawımen bılaýğı ötwin tekserwine |
1872 | 1874 | siz mindetti bolasız. |
1873 | 1875 | |
— | — | @@ -1877,7 +1879,7 @@ |
1878 | 1880 | biraq bar bettiñ üstine jazwğa bolmaýdı. |
1879 | 1881 | |
1880 | 1882 | <b>NAZAR SALIÑIZ!</b> |
1881 | | -Bul däripti betke qatañ jäne kenet özgeris jasawğa mümkin; |
| 1883 | +Bul äýgili betke qatañ jäne kenet özgeris jasawğa mümkin; |
1882 | 1884 | ärekettiñ aldınan osınıñ zardaptarın tüsingeniñizge batıl |
1883 | 1885 | bolıñız.", |
1884 | 1886 | 'movepagetalktext' => "Kelesi sebepter '''bolğanşa''' deýin, talqılaw beti özdiktik birge jıljıtıladı: |
— | — | @@ -2042,8 +2044,8 @@ |
2043 | 2045 | 'tooltip-ca-nstab-help' => 'Anıqtıma betin qaraw', |
2044 | 2046 | 'tooltip-ca-nstab-category' => 'Sanat betin qaraw', |
2045 | 2047 | 'tooltip-minoredit' => 'Osını şağın tüzetw dep belgilew', |
2046 | | -'tooltip-save' => 'Tüzetwiñizdi saqtaw', |
2047 | | -'tooltip-preview' => 'Saqtawdıñ aldınan tüzetwiñizdi qarap şığıñız!', |
| 2048 | +'tooltip-save' => 'Jasağan özgeristeriñizdi saqtaw', |
| 2049 | +'tooltip-preview' => 'Saqtawdıñ aldınan jasağan özgeristeriñizdi qarap şığıñız!', |
2048 | 2050 | 'tooltip-diff' => 'Mätinge qandaý özgeristerdi jasağanıñızdı qaraw.', |
2049 | 2051 | 'tooltip-compareselectedversions' => 'Bettiñ eki nusqasınıñ aýırmasın qaraw.', |
2050 | 2052 | 'tooltip-watch' => 'Bul betti baqılaw tizimiñizge üstew', |
— | — | @@ -2135,7 +2137,7 @@ |
2136 | 2138 | 'spamprotectiontitle' => '«Spam»-nan qorğaýtın süzgi', |
2137 | 2139 | 'spamprotectiontext' => 'Bul bettiñ saqtawın «spam» süzgisi buğattadı. Bunıñ sebebi sırtqı torap siltemesinen bolwı mümkin.', |
2138 | 2140 | 'spamprotectionmatch' => 'Kelesi «spam» mätini süzgilengen: $1', |
2139 | | -'subcategorycount' => 'Bul sanatta {{PLURAL:$1|bir|$1}} tömengi sanat bar.', |
| 2141 | +'subcategorycount' => 'Bul sanatta {{PLURAL:$1|bir|$1}} sanatşa bar.', |
2140 | 2142 | 'categoryarticlecount' => 'Bul sanatta {{PLURAL:$1|bir|$1}} bet bar.', |
2141 | 2143 | 'category-media-count' => 'Bul sanatta {{PLURAL:$1|bir|$1}} faýl bar.', |
2142 | 2144 | 'listingcontinuesabbrev' => ' (jalğ.)', |
— | — | @@ -2168,7 +2170,7 @@ |
2169 | 2171 | 'rcpatroldisabledtext' => 'Jwıqtağı özgerister Küzeti qasïeti ağımda öşirilgen.', |
2170 | 2172 | 'markedaspatrollederror' => 'Küzette dep belgilenbeýdi', |
2171 | 2173 | 'markedaspatrollederrortext' => 'Küzette dep belgilew üşin nusqasın engiziñiz.', |
2172 | | -'markedaspatrollederror-noautopatrol' => 'Öziñizdiñ özgeristeriñizdi küzetke qoya almaýsız.', |
| 2174 | +'markedaspatrollederror-noautopatrol' => 'Öziñiz jasağan özgeristeriñizdi küzetke qoya almaýsız.', |
2173 | 2175 | |
2174 | 2176 | # Patrol log |
2175 | 2177 | 'patrol-log-page' => 'Küzet jwrnalı', |
— | — | @@ -2185,7 +2187,7 @@ |
2186 | 2188 | |
2187 | 2189 | # Media information |
2188 | 2190 | 'mediawarning' => "'''Nazar salıñız''': Bul faýl türinde qaskünemdi ämirdiñ bar bolwı ıqtïmal; faýldı jegip jüýeñizge zïyan keltirwiñiz mümkin.<hr />", |
2189 | | -'imagemaxsize' => 'Swret tüýindeme betindegi swrettiñ mölşerin şektewi:', |
| 2191 | +'imagemaxsize' => 'Sïpattaması betindegi swrettiñ mölşerin şektewi:', |
2190 | 2192 | 'thumbsize' => 'Nobaý mölşeri:', |
2191 | 2193 | 'widthheight' => '$1 × $2', |
2192 | 2194 | 'file-info' => 'Faýl mölşeri: $1, MIME türi: $2', |
— | — | @@ -2491,7 +2493,7 @@ |
2492 | 2494 | # Pseudotags used for GPSSpeedRef and GPSDestDistanceRef |
2493 | 2495 | 'exif-gpsspeed-k' => 'km/h', |
2494 | 2496 | 'exif-gpsspeed-m' => 'mil/h', |
2495 | | -'exif-gpsspeed-n' => 'J. tüýin', |
| 2497 | +'exif-gpsspeed-n' => 'knot', |
2496 | 2498 | |
2497 | 2499 | # Pseudotags used for GPSTrackRef, GPSImgDirectionRef and GPSDestBearingRef |
2498 | 2500 | 'exif-gpsdirection-t' => 'Şın bağıt', |
Index: branches/liquidthreads/languages/messages/MessagesDa.php |
— | — | @@ -1494,6 +1494,7 @@ |
1495 | 1495 | 'istemplate' => 'Skabelonmedtagning', |
1496 | 1496 | 'whatlinkshere-prev' => '{{PLURAL:$1|forrige|forrige $1}}', |
1497 | 1497 | 'whatlinkshere-next' => '{{PLURAL:$1|næste|næste $1}}', |
| 1498 | +'whatlinkshere-links' => '← henvisninger', |
1498 | 1499 | |
1499 | 1500 | # Block/unblock |
1500 | 1501 | 'blockip' => 'Bloker bruger', |
Index: branches/liquidthreads/languages/messages/MessagesDe.php |
— | — | @@ -1532,7 +1532,7 @@ |
1533 | 1533 | 'istemplate' => 'Vorlageneinbindung', |
1534 | 1534 | 'whatlinkshere-prev' => '{{PLURAL:$1|vorheriger|vorherige $1}}', |
1535 | 1535 | 'whatlinkshere-next' => '{{PLURAL:$1|nächster|nächste $1}}', |
1536 | | -'whatlinkshere-links' => '(← Links)', |
| 1536 | +'whatlinkshere-links' => '← Links', |
1537 | 1537 | |
1538 | 1538 | # Block/unblock |
1539 | 1539 | 'blockip' => 'IP-Adresse/Benutzer sperren', |
Index: branches/liquidthreads/languages/messages/MessagesZh_yue.php |
— | — | @@ -340,9 +340,9 @@ |
341 | 341 | 'categorypage' => '去睇分類頁', |
342 | 342 | 'viewtalkpage' => '睇討論', |
343 | 343 | 'otherlanguages' => '第啲語言', |
344 | | -'redirectedfrom' => '(由 $1 重新定向)', //REDIRECT |
345 | | -'redirectpagesub' => '重新定向頁', |
346 | | -'lastmodifiedat' => '呢一頁嘅最後修改係響$1 $2。', |
| 344 | +'redirectedfrom' => '(由$1跳轉過來)', //REDIRECT |
| 345 | +'redirectpagesub' => '跳轉頁', |
| 346 | +'lastmodifiedat' => '呢一頁嘅最後修改係響$1 $2。', |
347 | 347 | 'viewcount' => '呢一頁已經有$1人次睇過。', |
348 | 348 | 'copyright' => '響版度嘅內容係根據$1嘅條款發佈。', |
349 | 349 | 'protectedpage' => '受保護頁', |
— | — | @@ -1116,7 +1116,7 @@ |
1117 | 1117 | 'userstats' => '用戶統計', |
1118 | 1118 | 'sitestatstext' => "資料庫中而家有'''$1'''頁。 |
1119 | 1119 | 其中包括咗「討論」頁、關於{{SITENAME}}嘅頁、好短嘅「楔位」 |
1120 | | -文章、重新定向, 以及其他唔計入內容嘅頁。 |
| 1120 | +文章、跳轉,以及其他唔計入內容嘅頁。 |
1121 | 1121 | 唔計非內容頁在內,則總共有'''$2'''頁可能會計入正規嘅內容。 |
1122 | 1122 | |
1123 | 1123 | '''$8''' 個檔案已經上載。 |
— | — | @@ -1248,7 +1248,7 @@ |
1249 | 1249 | 先可以傳送電郵畀其他用戶。", |
1250 | 1250 | 'emailuser' => '發電郵畀呢位用戶', |
1251 | 1251 | 'emailpage' => '發電郵畀用戶', |
1252 | | -'emailpagetext' => '如果呢位用戶已經喺佢嘅用戶使用偏好入邊填咗個合法嘅電郵地址,以下表格會發送單單一條訊息。 |
| 1252 | +'emailpagetext' => '如果呢位用戶已經喺佢嘅用戶使用偏好入邊填咗個合法嘅電郵地址,以下表格會發送單單一條信息。 |
1253 | 1253 | 你喺你嘅用戶喜好設定入面填寫嘅電郵地址會出現喺呢封電郵「由」嘅地址度,以便收件人可以回覆到。', |
1254 | 1254 | 'usermailererror' => '目標郵件地址返回錯誤:', |
1255 | 1255 | 'defemailsubject' => "{{SITENAME}} 電郵", |
— | — | @@ -1263,7 +1263,7 @@ |
1264 | 1264 | 'emailccme' => '傳送一個我嘅信息電郵畀我。', |
1265 | 1265 | 'emailccsubject' => '複製你嘅信息到 $1: $2', |
1266 | 1266 | 'emailsent' => '電郵已傳送', |
1267 | | -'emailsenttext' => '你嘅電郵訊息已傳送。', |
| 1267 | +'emailsenttext' => '你嘅電郵信息已傳送。', |
1268 | 1268 | |
1269 | 1269 | # Watchlist |
1270 | 1270 | 'watchlist' => '監視清單', |
— | — | @@ -1515,6 +1515,7 @@ |
1516 | 1516 | 'istemplate' => '包含', |
1517 | 1517 | 'whatlinkshere-prev' => '前$1版', |
1518 | 1518 | 'whatlinkshere-next' => '後$1版', |
| 1519 | +'whatlinkshere-links' => '(← 連結)', |
1519 | 1520 | |
1520 | 1521 | # Block/unblock IP |
1521 | 1522 | # |
— | — | @@ -1699,10 +1700,10 @@ |
1700 | 1701 | 'allmessagesname' => '名稱', |
1701 | 1702 | 'allmessagesdefault' => '預設文字', |
1702 | 1703 | 'allmessagescurrent' => '現時文字', |
1703 | | -'allmessagestext' => '以下係 MediaWiki 空間名入邊現有系統訊息嘅清單。', |
| 1704 | +'allmessagestext' => '以下係 MediaWiki 空間名入邊現有系統信息嘅清單。', |
1704 | 1705 | 'allmessagesnotsupportedUI' => '呢個網站嘅{{ns:special}}:AllMessages唔支持你現時嘅介面語言<b>$1</b>。', |
1705 | 1706 | 'allmessagesnotsupportedDB' => '唔可以用\'\'\'{{ns:special}}:AllMessages\'\'\',因為\'\'\'$wgUseDatabaseMessages\'\'\'已經閂咗。', |
1706 | | -'allmessagesfilter' => '訊息名過濾(器):', |
| 1707 | +'allmessagesfilter' => '信息名過濾(器):', |
1707 | 1708 | 'allmessagesmodified' => '只顯示修改過嘅', |
1708 | 1709 | |
1709 | 1710 | |
— | — | @@ -2294,7 +2295,7 @@ |
2295 | 2296 | 'unit-pixel' => 'px', |
2296 | 2297 | |
2297 | 2298 | # HTML dump |
2298 | | -'redirectingto' => '重新定向到[[$1]]...', |
| 2299 | +'redirectingto' => '跳轉去[[$1]]...', |
2299 | 2300 | |
2300 | 2301 | # action=purge |
2301 | 2302 | 'confirm_purge' => "肯定要洗咗呢版個快取版本?\n\n$1", |
— | — | @@ -2334,7 +2335,7 @@ |
2335 | 2336 | # Auto-summaries |
2336 | 2337 | 'autosumm-blank' => '移除緊響嗰一版嘅全部內容', |
2337 | 2338 | 'autosumm-replace' => '用 \'$1\' 取代緊嗰一版', |
2338 | | -'autoredircomment' => '重新定向緊到[[$1]]', # This should be changed to the new naming convention, but existed beforehand. |
| 2339 | +'autoredircomment' => '跳緊轉到[[$1]]', # This should be changed to the new naming convention, but existed beforehand. |
2339 | 2340 | 'autosumm-new' => '新頁: $1', |
2340 | 2341 | |
2341 | 2342 | # Size units |
Index: branches/liquidthreads/RELEASE-NOTES |
— | — | @@ -43,7 +43,13 @@ |
44 | 44 | * Introducing 'frameless' keyword to [[Image:]] syntax which respects the |
45 | 45 | user preferences for image width like 'thumb' but without a frame. |
46 | 46 | * (bug 7960) Link to "what links here" for each "what links here" entry |
| 47 | +* Added support for configuration of an arbitrary number of commons-style |
| 48 | + file repositories. |
| 49 | +* Added a Content-Disposition header to thumb.php output |
| 50 | +* Improved thumb.php error handling |
| 51 | +* Display file history on local image description pages of shared images |
47 | 52 | |
| 53 | + |
48 | 54 | == Bugfixes since 1.10 == |
49 | 55 | |
50 | 56 | * (bug 9712) Use Arabic comma in date/time formats for Arabic and Farsi |
— | — | @@ -93,7 +99,9 @@ |
94 | 100 | * (bug 7899) Added \hline and \vline to the list of allowed TeX commands |
95 | 101 | * (bug 7993) support mathematical symbol classes |
96 | 102 | * (bug 10007) Allow Block IP to work with Postgrs again. |
| 103 | +* Add Google Wireless Transcoder to the Unicode editing blacklist |
97 | 104 | |
| 105 | + |
98 | 106 | == MediaWiki API changes since 1.10 == |
99 | 107 | |
100 | 108 | (For ongoing development discussion, see http://www.mediawiki.org/wiki/API) |
— | — | @@ -136,16 +144,19 @@ |
137 | 145 | * Spanish (es) |
138 | 146 | * Farsi (fa) |
139 | 147 | * Finnish (fi) |
| 148 | +* Võro (fiu-vro) |
140 | 149 | * French (fr) |
141 | 150 | * Hakka (hak) |
142 | 151 | * Hebrew (he) |
143 | 152 | * Indonesian (id) |
144 | 153 | * Italian (it) |
145 | 154 | * Japanese (ja) |
| 155 | +* Georgian (ka) |
146 | 156 | * Kabyle (kab) |
147 | 157 | * Kazakh (kk) |
148 | 158 | * Kurdish (ku) |
149 | 159 | * Lithuanian (lt) |
| 160 | +* Burmese (my) |
150 | 161 | * Norwegian (no) |
151 | 162 | * Polish (pl) |
152 | 163 | * Russian (ru) |
— | — | @@ -153,6 +164,7 @@ |
154 | 165 | * Somali (so) |
155 | 166 | * Sundanese (su) |
156 | 167 | * Swedish (sv) |
| 168 | +* Old Chinese / Late Middle Chinese (zh-classical) |
157 | 169 | * Chinese (PRC) (zh-cn) |
158 | 170 | * Chinese (Taiwan) (zh-tw) |
159 | 171 | * Cantonese (zh-yue) |
Property changes on: branches/liquidthreads |
___________________________________________________________________ |
Modified: svnmerge-integrated |
160 | 172 | - /trunk/phase3:1-22554 |
161 | 173 | + /trunk/phase3:1-22586 |