PHP event-based XML parser

被解析的XML文件 book.xml

            Rasmus Lerdorf
            Kevin Tatroe
            Peter MacIntyre
        
        1-5692-610-2
        A great book!
            Rasmus Lerdorf
        
        1-56592-769-9
        It really does fit in your pocket

Parser XML

<html>
    <head>My Library</head>

    <body>
        <?php
        error_reporting(0);

        class BookList {

            const FIELD_TYPE_SINGLE = 1;
            const FIELD_TYPE_ARRAY = 2;
            const FIELD_TYPE_CONTAINER = 3;

            var $parser;
            var $record;
            var $currentField = '';
            var $fieldType;
            var $endsRecord;
            var $records;

            function __construct($filename) {
                $this->parser = xml_parser_create();
                xml_set_object($this->parser, $this);
                xml_set_element_handler($this->parser, "elementStarted", "elementEnded");
                xml_set_character_data_handler($this->parser, "handleCdate");

                $this->fieldType = array(
                    'title' => self::FIELD_TYPE_SINGLE,
                    'author' => self::FIELD_TYPE_ARRAY,
                    'isbn' => self::FIELD_TYPE_SINGLE,
                    'comment' => self::FIELD_TYPE_SINGLE,
                );

                $this->endsRecord = array('book' => true);

                $xml = join('', file($filename));
                xml_parse($this->parser, $xml);

                xml_parser_free($this->parser);
            }

            function elementStarted($parser, $element, &$attributes) {
                $element = strtolower($element);

                if ($this->fieldType[$element] != 0) {
                    $this->currentField = $element;
                } else {
                    $this->currentField = '';
                }
            }

            function elementEnded($parser, $element) {
                $element = strtolower($element);

                if ($this->endsRecord[$element]) {
                    $this->records[] = $this->record;
                    $this->record = array();
                }

                $this->currentField = '';
            }

            function handleCdate($parser, $text) {
                if ($this->fieldType[$this->currentField] == self::FIELD_TYPE_SINGLE) {
                    $this->record[$this->currentField] .= $text;
                } else if ($this->fieldType[$this->currentField] == self::FIELD_TYPE_ARRAY) {
                    $this->record[$this->currentField][] = $text;
                }
            }

            function showMenu() {
                echo "<table>\n";

                foreach ($this->records as $book) {
                    echo "<tr>";
                    echo "<th><a href=\"{$_SERVER['PHP_SELF']}?isbn={$book['isbn']}\">";
                    echo "{$book['title']}</a></th>";
                    echo "<td>" . join(', ', $book['author']) . "</td>\n";
                    echo "</tr>\n";
                }
                echo "</table>\n";
            }

            function showBook($isbn) {
                foreach ($this->records as $book) {
                    if ($book['isbn'] != $isbn) {
                        continue;
                    }
                    echo "<p><b>{$book['title']}</b> by " . join(', ', $book['author']) . "<br />";
                    echo "ISBN: {$book['isbn']}<br />";
                    echo "Commit: {$book['comment']}</p>\n";
                }
                echo "<p>Back to the <a href=\"{$_SERVER['PHP_SELF']}\">list of books</a>. </p>";
            }

        }

        $library = new BookList("books.xml");

        if (isset($_GET['isbn'])) {
            $library->showBook($_GET['isbn']);
        } else {
            $library->showMenu();
        }
        ?>

    </body>
</html>

ref: 《Programming PHP》 p.280

Android 对大图的处理

Scale big bitmap and set Keyguard Wallpaper

private void processBigBitmapAndSetKeyguardWallpaper(Uri _uri) {

            InputStream inStream = null; //receive from uri
            InputStream reOpenStream = null; //Raise efficiency and avoid OOM
            InputStream outStream = null; //send to keyguard
            Uri uri = _uri;

            try {
                inStream = mContext.getContentResolver().openInputStream(uri);

                //API > 13
                WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
                Display display = wm.getDefaultDisplay();
                Point point = new Point();
                display.getRealSize(point);

                BitmapFactory.Options opts = new BitmapFactory.Options();

                // For test the bitmap, just get the bitmap size, will not allocate memory for the big Bitmap
                opts.inJustDecodeBounds = true;
                BitmapFactory.decodeStream(inStream, null, opts);
                
                // Then scale the big bitmap
                int scale1 = Math.max(opts.outHeight, opts.outWidth)
                                    / Math.max(point.x, point.y);
                int scale2 = Math.min(opts.outHeight, opts.outWidth)
                                    / Math.min(point.x, point.y);

                opts.inSampleSize = Math.max(scale1, scale2);
                opts.inJustDecodeBounds = false;

                reOpenStream = mContext.getContentResolver().openInputStream(uri);

                Bitmap scaledBitmap = BitmapFactory.decodeStream(reOpenStream, null, opts);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
                scaledBitmap.recycle();
                outStream = new ByteArrayInputStream(baos.toByteArray());
                WallpaperManager wallpaperManager = WallpaperManager
                        .getInstance(mContext);
                wallpaperManager.setKeyguardStream(outStream);

            } catch (FileNotFoundException e) {
                Log.d(TAG, uri.toString() + " not found" + e.toString());
            } catch (IOException e) {
                Log.d(TAG, "set keyguard error" + e.toString());
            } finally {
                try {
                    if (null != inStream)
                        inStream.close();

                    if(null != outStream)
                        outStream.close();

                    if(null != reOpenStream)
                        reOpenStream.close();

                } catch (IOException e) {
                    Log.d(TAG, "set keyguard error" + e.toString());
                }
            }
            return true;
        }

ref: http://blog.hesheyou.me/post/crop-large-image-with-android

解决 KitKat 对SD卡的读写限制

前提是你有Android源码或者设备已经ROOT,如果不考虑系统安全或者CTS等条件,可以选择修改系统文件来完全开放KitKat对SD卡的读写权限,让第三方APP以KitKat之前版本相同的方式操作SD卡。

修改文件:/system/etc/permissions/platform.xml

原始内容:

    <permission name="android.permission.WRITE_EXTERNAL_STORAGE" >             
        <group gid="sdcard_r" />          
        <group gid="sdcard_rw" />                                            
    </permission> 

修改后:

    <permission name="android.permission.WRITE_EXTERNAL_STORAGE" >             
        <group gid="sdcard_r" />          
        <group gid="sdcard_rw" />                                            
        <group gid="media_rw" />
    </permission>

修改之后第三方APP只需要跟以前一样申请<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE” />来读写整个SD卡了。

ref: http://developer.huawei.com/devunion/ui/newsDetail.html?news=/devunion/news/n_00033.html

Android4.4 对 Secondary External Storage 的访问

Android在KitKat之后对Secondary External Storage(SES)的访问做了很大的修改。普通APP不再可以随意写整个SES,只能在属于自己的目录中进行写操作,比如Android/data/com.lnmcc.testsdcard,最后部分为APP的包名。并且APP在访问自己的私有文件夹时不再需要任何的权限。

在我的系统中,我把sd卡挂载到了/storage/sdcard1。 下面的代码片段将获取APP在SES上的的私有目录路径,之后就可以在这个路径下做读写操作了。

        private String SDCard1 = null;

        File[] files = getExternalFilesDirs(null);
        for (File file : files) {
            Log.d(TAG, file.getAbsolutePath());
            // sdcard1 is the external storage(SD card) on my platform
            String path = file.getAbsolutePath();
            if (path.contains("/storage/sdcard1")) {
                // found it
                SDCard1 = path;
                Log.d(TAG, SDCard1);
                break;
            }
        }

完整的DEMO:

public class MainActivity extends Activity implements OnClickListener {

    private static final String TAG = "TestSDCard";

    private String SDCard1 = null;

    private Button listBtn;
    private Button testWriteBtn;
    private TextView txt;
    private StringBuilder sb;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        File[] files = getExternalFilesDirs(null);
        for (File file : files) {
            Log.d(TAG, file.getAbsolutePath());
            // sdcard1 is the external storage(SD card) on my platform
            String path = file.getAbsolutePath();
            if (path.contains("/storage/sdcard1")) {
                // found it
                SDCard1 = path;
                Log.d(TAG, SDCard1);
                break;
            }
        }

        sb = new StringBuilder();

        listBtn = (Button) findViewById(R.id.listBtn);
        listBtn.setOnClickListener(this);

        testWriteBtn = (Button) findViewById(R.id.testWriteBtn);
        testWriteBtn.setOnClickListener(this);

        txt = (TextView) findViewById(R.id.txt);
    }

    @Override
    public void onClick(View v) {
        int btnId = v.getId();

        switch (btnId) {
        case R.id.listBtn:
            new AsyncTask<Void, Void, Void>() {

                @Override
                protected void onPreExecute() {
                    listBtn.setEnabled(false);
                }

                @Override
                protected void onPostExecute(Void result) {
                    txt.setText(sb.toString());
                    listBtn.setEnabled(true);
                }

                @Override
                protected Void doInBackground(Void... params) {
                    sb.delete(0, sb.length());
                    readFile(SDCard1);
                    return null;
                }
            }.execute();
            break;

        case R.id.testWriteBtn:

            new AsyncTask<Void, Void, Void>() {

                @Override
                protected void onPreExecute() {
                    testWriteBtn.setEnabled(false);
                }

                @Override
                protected void onPostExecute(Void result) {
                    sb.delete(0, sb.length());
                    readFile(SDCard1);
                    txt.setText(sb.toString());
                    testWriteBtn.setEnabled(true);
                }

                @Override
                protected Void doInBackground(Void... params) {
                    newFile(SDCard1);
                    return null;
                }
            }.execute();
            break;

        default:
            break;

        }
    }

    private void newFile(String path) {
        File file = null;

        try {
            file = File.createTempFile("TestSDCard", ".txt", new File(path));
            Log.d(TAG, file.getAbsolutePath());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void readFile(String path) {
        File file = new File(path);
        if (file.isDirectory()) {
            String[] subFiles = file.list();

            sb.append("Directory: ");
            sb.append(file.getName());
            sb.append("\n");

            for (String subFile : subFiles) {
                String subPath = file.getAbsolutePath() + "/" + subFile;
                Log.d(TAG, subPath);
                readFile(subPath);
            }
        } else {
            sb.append("file: ");
            sb.append(file.getName());
            sb.append("\n");
        }
    }
}

github: KitKatSecondaryExternalStorageRWDemo.git ref: https://source.android.com/devices/storage/ ref: https://developer.android.com/guide/topics/providers/document-provider.html ref: http://blog.csdn.net/zjbpku/article/details/25161131

PHP 使用 FPDF 生成 Header 和 Footer

require("fpdf.php");
class MyPDF extends FPDF
{
    function header()
    {
        global $title;
        $this->setFont("Times", '', 12);
        $this->setDrawColor(0, 0, 180);
        $this->setFillColor(230, 0, 230);
        $this->setTextColor(0, 0, 255);
        $this->setLineWidth(1);

        $width = $this->getStringWidth($title) + 150;
        $this->cell($width, 9, $title, 1, 1, 'C', 1);
        $this->ln(10);
    }

    function footer()
    {
        //Position at 1.5 cm from bottom
        $this->setY(-15);
        $this->setFont("Arial", 'I', 8);
        $this->cell(0, 10,
        "This is the page footer -> Page {$this->pageNo()}/{nb}", 0, 0, 'C');
    }
}

$title = "FPDF Library Page Header";

$pdf = new MyPDF('P', 'mm', 'Letter');
$pdf->aliasNbPages();
$pdf->addPage();
$pdf->setFont("Times", '', 24);
$pdf->cell(0, 0, "some text at the top of the page", 0, 0, 'L');
$pdf->ln(225);
$pdf->cell(0, 0, "More text toward the bottom", 0, 0, 'C');
$pdf->addPage();
$pdf->setFont("Arial", 'B', 15);
$pdf->cell(0, 0, "Top of page 2 after header", 0, 1, 'C');
$pdf->output();

ref: ProgrammerPHP p.259